spring mvc基于token防止重复提交验证

本文介绍了如何在Spring MVC中使用Token来防止重复提交。主要思路是通过配置拦截器,为页面请求生成随机Token并存入Session,表单提交时校验Token匹配并立即删除,以此达到防止重复提交的目的。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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  

本人做了一些修改



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值