Struts2 的token原理

在页面加载时,<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
Java代码   收藏代码
  1. /*    */   
  2. /*    */ public class TokenTag extends AbstractUITag  
  3. /*    */ {  
  4. /*    */   private static final long serialVersionUID = 722480798151703457L;  
  5. /*    */   
  6. /*    */   public Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res)  
  7. /*    */   {  
  8. /* 41 */     return new Token(stack, req, res);  
  9. /*    */   }  
  10. /*    */ }  
 然后条用父类相应帮助方法
Java代码   收藏代码
  1. public class TokenHelper  
  2. /*     */ {  
  3.                  //默认的token名字可以自己定义  
  4. /*     */    public static final String DEFAULT_TOKEN_NAME = "struts.token";  
  5. /*     */    public static final String TOKEN_NAME_FIELD = "struts.token.name";  
  6. /*  48 */   private static final Logger LOG = LoggerFactory.getLogger(TokenHelper.class);  
  7. /*  49 */   private static final Random RANDOM = new Random();  
  8. /*     */   
  9. /*     */   public static String setToken()  
  10. /*     */   {  
  11. /*  58 */     return setToken("struts.token");  
  12. /*     */   }  
  13. /*     */   //当页面初始化的时候调用setToken/*     */     
  14.           public static String setToken(String tokenName)  
  15. /*     */   {  
  16. /*  68 */     Map session = ActionContext.getContext().getSession();  
  17. /*  69 */     String token = generateGUID();  
  18. /*     */     try {  
  19.                     //放入session中,键为struts.token:值token为一个随机数值  
  20. /*  71 */       session.put(tokenName, token);  
  21. /*     */     }  
  22. /*     */     catch (IllegalStateException e)  
  23. /*     */     {  
  24. /*  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();  
  25. /*  76 */       LOG.error(msg, e, new String[0]);  
  26. /*  77 */       throw new IllegalArgumentException(msg);  
  27. /*     */     }  
  28. /*     */   
  29. /*  80 */     return token;  
  30. /*     */   }  
  31. /*     */   //所得token的值  
  32. /*     */   public static String getToken()  
  33. /*     */   {  
  34. /*  90 */     return getToken("struts.token");  
  35. /*     */   }  
  36. /*     */   
  37. /*     */   public static String getToken(String tokenName)  
  38. /*     */   {  
  39. /* 100 */     if (tokenName == null) {  
  40. /* 101 */       return null;  
  41. /*     */     }  
  42. /* 103 */     Map params = ActionContext.getContext().getParameters();  
  43. /* 104 */     String[] tokens = (String[])(String[])params.get(tokenName);  
  44. /*     */   
  45. /* 107 */     if ((tokens == null) || (tokens.length < 1)) {  
  46. /* 108 */       LOG.warn("Could not find token mapped to token name " + tokenName, new String[0]);  
  47. /*     */   
  48. /* 110 */       return null;  
  49. /*     */     }  
  50. /*     */   
  51. /* 113 */     String token = tokens[0];  
  52. /*     */   
  53. /* 115 */     return token;  
  54. /*     */   }  
  55. /*     */    //所得struts.token.name 隐藏表达欲的值 token.name  
  56. /*     */   public static String getTokenName()  
  57. /*     */   {  
  58. /* 124 */     Map params = ActionContext.getContext().getParameters();  
  59. /*     */   
  60. /* 126 */     if (!params.containsKey("struts.token.name")) {  
  61. /* 127 */       LOG.warn("Could not find token name in params."new String[0]);  
  62. /*     */   
  63. /* 129 */       return null;  
  64. /*     */     }  
  65. /*     */   
  66. /* 132 */     String[] tokenNames = (String[])(String[])params.get("struts.token.name");  
  67. /*     */   
  68. /* 135 */     if ((tokenNames == null) || (tokenNames.length < 1)) {  
  69. /* 136 */       LOG.warn("Got a null or empty token name."new String[0]);  
  70. /*     */   
  71. /* 138 */       return null;  
  72. /*     */     }  
  73. /*     */   
  74. /* 141 */     String tokenName = tokenNames[0];  
  75. /*     */   
  76. /* 143 */     return tokenName;  
  77. /*     */   }  
  78. /*     */    //验证token是否重复提交  
  79. /*     */   public static boolean validToken()  
  80. /*     */   {  
  81. /* 153 */     String tokenName = getTokenName();  
  82. /*     */   
  83. /* 155 */     if (tokenName == null) {  
  84. /* 156 */       if (LOG.isDebugEnabled())  
  85. /* 157 */         LOG.debug("no token name found -> Invalid token "new String[0]);  
  86. /* 158 */       return false;  
  87. /*     */     }  
  88. /*     */         //通过tokenName获得页面初始化token的值  
  89. /* 161 */     String token = getToken(tokenName);  
  90. /*     */   
  91. /* 163 */     if (token == null) {  
  92. /* 164 */       if (LOG.isDebugEnabled())  
  93. /* 165 */         LOG.debug("no token found for token name " + tokenName + " -> Invalid token "new String[0]);  
  94. /* 166 */       return false;  
  95. /*     */     }  
  96. /*     */       //获取session中的token...  
  97. /* 169 */     Map session = ActionContext.getContext().getSession();  
  98. /* 170 */     String sessionToken = (String)session.get(tokenName);  
  99. /*     */       //判断session中的token值和页面上的token值是否相等  
  100. /* 172 */     if (!token.equals(sessionToken)) {  
  101. /* 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]);  
  102. /*     */   
  103. /* 177 */       return false;  
  104. /*     */     }  
  105. /*     */   
  106. /* 181 */     session.remove(tokenName);  
  107. /*     */   
  108. /* 183 */     return true;  
  109. /*     */   }  
  110. /*     */   //产生随机数  
  111. /*     */   public static String generateGUID() {  
  112. /* 187 */     return new BigInteger(165, RANDOM).toString(36).toUpperCase();  
  113. /*     */   }  
  114. /*     */ }  
 
    当一个表单提交的时候。。。经过token拦截器。就相当于filter.Spring Aop 一样的类,具体配置如下
Java代码   收藏代码
  1. <action name="token" class="com.bhr.ssh.json.action.TokenAction">  
  2.             <interceptor-ref name="defaultStack" />  
  3.             <interceptor-ref name="token" />  
  4.             <result name="invalid.token">/token.jsp</result>                          
  5.             <result>/token.jsp</result>  
  6.         </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中的被保存的随机数进行对比这两者相同服务器认为是第一次提交。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值