spring mvc基於token防止重複提交驗證

spring mvc基於token防止重複提交驗證

實現思路:

在springmvc配置文件中加入攔截器的配置,攔截兩類請求,一類是到頁面的,一類是提交表單的。當轉到頁面的請求到來時,生成token的名字和token值,放入session,在頁面表單的隱藏域顯示。

當表單請求提交時,攔截器得到參數中的tokenName和token,然後到session中去取token值,如果能匹配上,請求就通過,不能匹配上就不通過。這裏的token生成時也是隨機的,每次請求都不一樣。而從session中取token值時,會立即將其刪除(刪與讀是原子的,無線程安全問題)。

一、首先創建一個token處理類  ,這裏的類名叫 TokenHandler

package com.base.utils;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;

/**
 * 創建時間:2017年4月5日 下午5:56:31 
 * 項目名稱:tra02
 * 
 * @author hc
 * @version 1.0 
 * 文件名稱:TokenHandler.java 
 * 類說明:
 */
public class TokenHandler {
	private static Logger logger = Logger.getLogger(TokenHandler.class);

	static Map<String, String> springmvc_token = null;

	// 生成一個唯一值的token
	@SuppressWarnings("unchecked")
	public synchronized static String generateGUID(HttpSession session) {
		String token = "";
		try {
			Object obj = session.getAttribute("SPRINGMVC.TOKEN");
			if (obj != null)
				springmvc_token = (Map<String, String>) session.getAttribute("SPRINGMVC.TOKEN");
			else
				springmvc_token = new HashMap<String, String>();
			token = new BigInteger(165, new Random()).toString(36).toUpperCase();
			springmvc_token.put(Constants.DEFAULT_TOKEN_NAME + "." + token, token);
			session.setAttribute("SPRINGMVC.TOKEN", springmvc_token);
			Constants.TOKEN_VALUE = token;
			// System.out.println(session.getAttribute("SPRINGMVC.TOKEN"));
		} catch (IllegalStateException e) {
			logger.error("generateGUID() mothod find bug,by token session...");
		}
		return token;
	}

	// 驗證表單token值和session中的token值是否一致
	@SuppressWarnings("unchecked")
	public static boolean validToken(HttpServletRequest request) {
		String inputToken = getInputToken(request);

		if (inputToken == null) {
			logger.warn("令牌是不是有效的。inputtoken是空的");
			return false;
		}

		HttpSession session = request.getSession();
		Map<String, String> tokenMap = (Map<String, String>) session.getAttribute("SPRINGMVC.TOKEN");
		if (tokenMap == null || tokenMap.size() < 1) {
			logger.warn("token is not valid!sessionToken is NULL");
			return false;
		}
		String sessionToken = tokenMap.get(Constants.DEFAULT_TOKEN_NAME + "." + inputToken);
		if (!inputToken.equals(sessionToken)) {
			logger.warn("token is not valid!inputToken='" + inputToken + "',sessionToken = '" + sessionToken + "'");
			return false;
		}
		tokenMap.remove(Constants.DEFAULT_TOKEN_NAME + "." + inputToken);
		session.setAttribute("SPRINGMVC.TOKEN", tokenMap);

		return true;
	}

	// 獲取表單中token值
	@SuppressWarnings("unchecked")
	public static String getInputToken(HttpServletRequest request) {
		Map params = request.getParameterMap();
		System.out.println(request.getSession().getAttribute("SPRINGMVC.TOKEN"));
		if (!params.containsKey(Constants.DEFAULT_TOKEN_NAME)) {
			logger.warn("無法找到令牌名稱參數。");
			return null;
		}

		String[] tokens = (String[]) (String[]) params.get(Constants.DEFAULT_TOKEN_NAME);

		if ((tokens == null) || (tokens.length < 1)) {
			logger.warn("得到空或空的令牌名稱。");
			return null;
		}
		String temp = tokens[0];
		String inputtoken = temp.substring(temp.indexOf("=") + 1, (temp.length()) - 1);
		return inputtoken;
	}
}

二、建立常量配置類Constabts

package com。base.utils;

/**
 * 創建時間:2017年4月5日 下午5:57:58 
 * 項目名稱:traffic02
 * 
 * @author hc
 * @version 1.0 
 * 文件名稱:Constants.java 
 * 類說明:
 */
public class Constants {
	
	public static String DEFAULT_TOKEN_MSG_JSP = "add.jsp";
	public static String TOKEN_VALUE;
	public static String DEFAULT_TOKEN_NAME = "springMVC.token";
	
}

三、前端頁面 主要是隱藏域

<%@page import="java.util.Map"%>
<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
	<div align="center">
	<form action="user/add" method="post" >
	
	<input type="hidden" name="springMVC.token" value="<%=session.getAttribute("SPRINGMVC.TOKEN")%>" >
	名字:<input type="text" name="username">
	密碼:<input type="password" name="password"/>
	<input type="submit" value="提交">
	</form>
	
	</div>
</body>
</html>

四、controller不用多寫什麼,能跳轉舉行

package com.traffic.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

/**  
* 創建時間:2017年4月5日 下午1:43:00  
* 項目名稱:tra  
* @author hc  
* @version 1.0   
* 文件名稱:UserController.java  
* 類說明:  
*/
@Controller
@RequestMapping("/user")
public class UserController {
	
	@RequestMapping("/toadd")
	public String toadd(Model model){
		
		return "forward:/add.jsp";
	}
	
	@RequestMapping("/add")
	public String add(String username,String password,Model model){
		
		System.out.println("suc");
		return "forward:/suc.jsp";
	}
}
 
五、重點是攔截器一個生成token,一個驗證token。

public class TokenHandlerInterceptor implements HandlerInterceptor{
 
 
    public void afterCompletion(HttpServletRequest arg0,
            HttpServletResponse arg1, Object arg2, Exception arg3)
            throws Exception {
    }
 
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
            Object arg2, ModelAndView arg3) throws Exception {
        TokenHandler.generateGUID(request.getSession());
    }
 
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
            Object arg2) throws Exception {
        return true;
    }
 
}
 
 
 
/**
 * @Title
 * @author 
 * @date 
 */
public class TokenValidInterceptor implements HandlerInterceptor{
 
    public void afterCompletion(HttpServletRequest request,
            HttpServletResponse response, Object arg2, Exception arg3)
            throws Exception {
    }
 
    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
            Object arg2, ModelAndView arg3) throws Exception {
         
    }
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
            Object arg2) throws Exception {
        if(!TokenHandler.validToken(request)){
            response.sendRedirect(Constants.DEFAULT_TOKEN_MSG_JSP);
            return false;
        }
    return true;
    }
 
}

六、當然 springmvc要配置攔截器

<mvc:interceptor>
            <mvc:mapping path="/index.do" />-->這個請求返回的是你有token的頁面
            <bean class="com.dengyang.interceptor.TokenHandlerInterceptor" />
        </mvc:interceptor>
        <mvc:interceptor>
            <mvc:mapping path="/indexSubmit.do" />-->這個是提交請求
            <bean class="com.dengyang.interceptor.TokenValidInterceptor" />
        </mvc:interceptor>
 

七、本方案如果不足之處,請大神們指教;

聲明:本方案源於

http://www.oschina.net/code/snippet_100825_21906  

本人做了一些修改



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章