[置顶] Struts2 的token原理
2016-03-10 16:05
387 查看
在页面加载时,<s: token />产生一个GUID(Globally Unique Identifier,全局唯一标识符)值的隐藏输入框如:
<
input
type
="hidden"
name
="struts.token.name"
value
="struts.token"
/>
<
input
type
="hidden"
name
="struts.token"
value
="BXPNNDG6BB11ZXHPI4E106CZ5K7VNMHR"
/>
同时,将GUID放到会话(session)中;在执行action之前,“token”拦截器将会话token与请求token比较,如果两者相同,则
将会话中的token删除并往下执行,否则向actionErrors加入错误信息。如此一来,如果用户通过某种手段提交了两次相同的请求,两个
token就会不同。
当加载页面的时候会调用<s: token /> 标签相应的tag
然后条用父类相应帮助方法
当一个表单提交的时候。。。经过token拦截器。就相当于filter.Spring Aop 一样的类,具体配置如下
然后在拦截器里面 获得页面上这个标签的value ; String tokenName = getToken();
<
input
type
="hidden"
name
="struts.token"
value
="BXPNNDG6BB11ZXHPI4E106CZ5K7VNMHR"
/>
然后在session里面找看是否有这个保存值,看是否session.getAttribute(tokenName);validToken();验证
一般来说第一次提交如果找到了,就把session.removeAttribute(tokenName);删除了。所以当重复提交的时候,tokenName 已经在session里面被清除了。没有保存在session里面,所以就。。。。。。。。。。。
总结:
通过Session Token :当客户端请求页面时,服务器会通过token标签生成一个随机数,并且将该随机数放到sesiion里面,然后将该随机数放到客户端,就是隐藏表单域,如果客户第一次提交,那么会将该随机数往服务器。被拦截。服务器接受到该随机数并且与session中的被保存的随机数进行对比这两者相同服务器认为是第一次提交。
<
input
type
="hidden"
name
="struts.token.name"
value
="struts.token"
/>
<
input
type
="hidden"
name
="struts.token"
value
="BXPNNDG6BB11ZXHPI4E106CZ5K7VNMHR"
/>
同时,将GUID放到会话(session)中;在执行action之前,“token”拦截器将会话token与请求token比较,如果两者相同,则
将会话中的token删除并往下执行,否则向actionErrors加入错误信息。如此一来,如果用户通过某种手段提交了两次相同的请求,两个
token就会不同。
当加载页面的时候会调用<s: token /> 标签相应的tag
/* */ /* */ public class TokenTag extends AbstractUITag /* */ { /* */ private static final long serialVersionUID = 722480798151703457L; /* */ /* */ public Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res) /* */ { /* 41 */ return new Token(stack, req, res); /* */ } /* */ }
然后条用父类相应帮助方法
public class TokenHelper /* */ { //默认的token名字可以自己定义 /* */ public static final String DEFAULT_TOKEN_NAME = "struts.token"; /* */ public static final String TOKEN_NAME_FIELD = "struts.token.name"; /* 48 */ private static final Logger LOG = LoggerFactory.getLogger(TokenHelper.class); /* 49 */ private static final Random RANDOM = new Random(); /* */ /* */ public static String setToken() /* */ { /* 58 */ return setToken("struts.token"); /* */ } /* */ //当页面初始化的时候调用setToken/* */ public static String setToken(String tokenName) /* */ { /* 68 */ Map session = ActionContext.getContext().getSession(); /* 69 */ String token = generateGUID(); /* */ try { //放入session中,键为struts.token:值token为一个随机数值 /* 71 */ session.put(tokenName, token); /* */ } /* */ catch (IllegalStateException e) /* */ { /* 75 */ String msg = "Error creating HttpSession due response is commited to client. You can use the CreateSessionInterceptor or create the HttpSession from your action before the result is rendered to the client: " + e.getMessage(); /* 76 */ LOG.error(msg, e, new String[0]); /* 77 */ throw new IllegalArgumentException(msg); /* */ } /* */ /* 80 */ return token; /* */ } /* */ //所得token的值 /* */ public static String getToken() /* */ { /* 90 */ return getToken("struts.token"); /* */ } /* */ /* */ public static String getToken(String tokenName) /* */ { /* 100 */ if (tokenName == null) { /* 101 */ return null; /* */ } /* 103 */ Map params = ActionContext.getContext().getParameters(); /* 104 */ String[] tokens = (String[])(String[])params.get(tokenName); /* */ /* 107 */ if ((tokens == null) || (tokens.length < 1)) { /* 108 */ LOG.warn("Could not find token mapped to token name " + tokenName, new String[0]); /* */ /* 110 */ return null; /* */ } /* */ /* 113 */ String token = tokens[0]; /* */ /* 115 */ return token; /* */ } /* */ //所得struts.token.name 隐藏表达欲的值 token.name /* */ public static String getTokenName() /* */ { /* 124 */ Map params = ActionContext.getContext().getParameters(); /* */ /* 126 */ if (!params.containsKey("struts.token.name")) { /* 127 */ LOG.warn("Could not find token name in params.", new String[0]); /* */ /* 129 */ return null; /* */ } /* */ /* 132 */ String[] tokenNames = (String[])(String[])params.get("struts.token.name"); /* */ /* 135 */ if ((tokenNames == null) || (tokenNames.length < 1)) { /* 136 */ LOG.warn("Got a null or empty token name.", new String[0]); /* */ /* 138 */ return null; /* */ } /* */ /* 141 */ String tokenName = tokenNames[0]; /* */ /* 143 */ return tokenName; /* */ } /* */ //验证token是否重复提交 /* */ public static boolean validToken() /* */ { /* 153 */ String tokenName = getTokenName(); /* */ /* 155 */ if (tokenName == null) { /* 156 */ if (LOG.isDebugEnabled()) /* 157 */ LOG.debug("no token name found -> Invalid token ", new String[0]); /* 158 */ return false; /* */ } /* */ //通过tokenName获得页面初始化token的值 /* 161 */ String token = getToken(tokenName); /* */ /* 163 */ if (token == null) { /* 164 */ if (LOG.isDebugEnabled()) /* 165 */ LOG.debug("no token found for token name " + tokenName + " -> Invalid token ", new String[0]); /* 166 */ return false; /* */ } /* */ //获取session中的token... /* 169 */ Map session = ActionContext.getContext().getSession(); /* 170 */ String sessionToken = (String)session.get(tokenName); /* */ //判断session中的token值和页面上的token值是否相等 /* 172 */ if (!token.equals(sessionToken)) { /* 173 */ LOG.warn(LocalizedTextUtil.findText(TokenHelper.class, "struts.internal.invalid.token", ActionContext.getContext().getLocale(), "Form token {0} does not match the session token {1}.", new Object[] { token, sessionToken }), new String[0]); /* */ /* 177 */ return false; /* */ } /* */ /* 181 */ session.remove(tokenName); /* */ /* 183 */ return true; /* */ } /* */ //产生随机数 /* */ public static String generateGUID() { /* 187 */ return new BigInteger(165, RANDOM).toString(36).toUpperCase(); /* */ } /* */ }
当一个表单提交的时候。。。经过token拦截器。就相当于filter.Spring Aop 一样的类,具体配置如下
<action name="token" class="com.bhr.ssh.json.action.TokenAction"> <interceptor-ref name="defaultStack" /> <interceptor-ref name="token" /> <result name="invalid.token">/token.jsp</result> <result>/token.jsp</result> </action>
然后在拦截器里面 获得页面上这个标签的value ; String tokenName = getToken();
<
input
type
="hidden"
name
="struts.token"
value
="BXPNNDG6BB11ZXHPI4E106CZ5K7VNMHR"
/>
然后在session里面找看是否有这个保存值,看是否session.getAttribute(tokenName);validToken();验证
一般来说第一次提交如果找到了,就把session.removeAttribute(tokenName);删除了。所以当重复提交的时候,tokenName 已经在session里面被清除了。没有保存在session里面,所以就。。。。。。。。。。。
总结:
通过Session Token :当客户端请求页面时,服务器会通过token标签生成一个随机数,并且将该随机数放到sesiion里面,然后将该随机数放到客户端,就是隐藏表单域,如果客户第一次提交,那么会将该随机数往服务器。被拦截。服务器接受到该随机数并且与session中的被保存的随机数进行对比这两者相同服务器认为是第一次提交。
相关文章推荐
- java 调 pro*c
- 面向GC的Java编程
- java.util.ResourceBundle使用详解
- ElasticSearch中设置排序Java
- Bigpipe学习笔记和java版实现
- 如何在eclipse jee中创建Maven project并且转换为Dynamic web project
- java rmi 防火墙
- Java EE 8 将支持 SSE 服务器端事件
- java tjws
- Hbase访问方式之Java API
- spring 多数据源 事物
- Java内存与垃圾回收调优
- Eclipse将引用了第三方jar包的Java项目打包成jar文件的两种方法
- Java 并发之 ConcurrentSkipListMap 简述
- spring 动态注册数据源
- Spring Bean 初始化过程
- java 线程池详解
- 详解Java GC的工作原理
- java file 海量文件处理
- JDK 源码设计 时间换空间 &amp; 空间换时间