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. /*    */ }  
/*    */ 
/*    */ 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);
/*    */   }
/*    */ }
 然后条用父类相应帮助方法
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. /*     */ }  
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 一样的类,具体配置如下
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>  
<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中的被保存的随机数进行对比这两者相同服务器认为是第一次提交。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值