这几天在网上闲逛,看到了几个关于spring的token二次提交问题,受到不少启发,于是自己动手根据自己公司的项目框架结构,制作了一个基于spring自动注入加上AOP的表单二次提交。
原理:建立两个注解类,一个进行token的设置,一个进行token的验证。在一个Aspect中,对这两个注解进行捕获并进行相应的验证。
废话不多说,下面是代码:
Token注解类,标记需要设置token的方法。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) //设定此注解对应的是方法。
public @interface Token { }
TokenValid注解类,标记需要验证token的方法。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TokenValid { }
TokenAspect类,对上面两个注解标识的方法的访问进行捕获并处理。
@Aspect
@Component
public class TokenAspect {
@Around("@annotation(token)") //可以直接捕获下面这个方法中参数所设定的注解类型
public void addToken(ProceedingJoinPoint joinPoint, Token token) throws Throwable{
Object[] args = joinPoint.getArgs();
String className = joinPoint.getTarget().getClass().getName();
for(Object a : args){
if(a != null && a instanceof HttpServletRequest){
HttpServletRequest request = (HttpServletRequest)a;
HttpSession session = request.getSession(true);
String flag = MD5Eencryption.md5_32(className + new Date().getTime()); //创建一个token的flag
session.setAttribute("TokenFlag" + className, flag);
request.setAttribute("token", flag);
joinPoint.proceed();
}
}
}
@Around("@annotation(tokenValid)")
public void checkToken(ProceedingJoinPoint joinPoint, TokenValid tokenValid) throws Throwable{
Object[] args = joinPoint.getArgs();
String className = joinPoint.getTarget().getClass().getName();
for(Object a : args){
if(a != null && a instanceof HttpServletRequest){
HttpServletRequest request = (HttpServletRequest)a;
System.out.println(request.getRequestedSessionId());
HttpSession session = request.getSession(true);
Object sessionFlag = session.getAttribute("TokenFlag" + className);
Object requestFlag = request.getParameter("token");
if(sessionFlag != null &&sessionFlag.equals(requestFlag)){ //验证结果一致,既为第一次提交,删除会话中存储的token,并继续执行方法。否则不做任何处理。
session.removeAttribute("TokenFlag" + className);
joinPoint.proceed();
}
}
}
}
}
使用:
需要工程开启spring的自动注入及AOP功能。
在需要设定token的方法前面增加注解:@Token,需要验证token的方法前面增加注解:@TokenValid。例如:
@TokenValid //会对访问此方法的请求验证token是否正确。
@RequestMapping(params = "method=save")
public String save(String type, HttpServletRequest request){
//...业务处理
}
前台页面的表单中,增加下面内容来提交token以便TokenValid的验证。
<input type="hidden" name="token" value="${requestScope.token}" />
如果表单为二次提交,将不会执行
@TokenValid标记的方法。
目前的问题:
1.局限了两个调用方法必须有一个参数为HttpServletRequest的对象。否则无法对请求和会话进行处理。
2.如果二次提交,没有返回提醒,直接返回的结果为空白页面。
来源:oschina
链接:https://my.oschina.net/u/1244985/blog/151553