在页面加载时,<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
/* */
/* */ 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中的被保存的随机数进行对比这两者相同服务器认为是第一次提交。
分享到:
相关推荐
在Web表单提交中,防止重复提交是一个常见的需求,而Struts2的Token机制就是为了应对这一问题而设计的。Token机制能确保用户只能提交一次表单,避免了由于网络延迟或误操作导致的重复数据录入。 ### 一、Token机制...
下面将详细阐述Struts2中Token机制的工作原理、配置以及使用方法。 1. Token机制概述: Token机制是通过在客户端(浏览器)和服务器之间传递一个唯一的标识符(Token)来防止表单的重复提交。当用户首次提交表单时...
Struts2提供了一种机制,即tokenSession,来解决这个问题。 首先,我们要理解什么是重复提交。在Web环境中,由于网络延迟或用户误操作,可能会导致同一个表单数据被多次提交,这就是重复提交。这种现象可能导致数据...
为了解决这个问题,Struts提供了一个名为“Token”的机制。 **一、Struts Token机制** Struts的Token机制主要用来防止用户意外或恶意的多次提交表单,例如在刷新页面时重复提交数据。它的工作原理如下: 1. **...
首先,我们需要在Struts2的配置文件(struts.xml)中添加Token拦截器。这个拦截器会处理Token的生成和验证过程。例如: ```xml <interceptor name="token" class="org.apache.struts2.interceptor....
Struts2是一个非常著名的Java Web框架,用于构建企业级应用。这个名为"struts2开发 token.rar"的压缩包文件可能包含了一个关于...通过研究和实践,开发者能够更好地理解Struts2的架构和工作原理,提升自己的开发技能。
2. 实现TokenAware接口:为了让ActionForm能够访问session中的令牌,需要让ActionForm实现`org.apache.struts.action.TokenAware`接口,并实现`setToken(String token)`方法。 3. 生成令牌:在Action中,如`execute...
二、Token机制的原理 Token机制的核心思想是在客户端和服务器之间创建一个一次性使用的凭证。当用户提交表单时,服务器会生成一个唯一的Token,并将其存储在一个临时的会话属性中,同时将其返回给客户端(通常是隐藏...
2. **传递Token**: 同时,该Token会被嵌入到表单中作为一个隐藏字段,以便于客户端提交时携带。 3. **验证Token**: 用户提交表单后,服务器会检查请求中的Token值是否与保存在Session中的Token值相匹配。 4. **更新...
#### 一、Token机制原理 Token机制是一种常见的防止重复提交的方法,其核心思想是为每一次表单提交生成一个唯一的Token值,并将这个Token值存储在客户端(通常是在表单中作为一个隐藏字段),同时也在服务器端记录...
Struts Token Dozer实例主要涉及的是Java开发中的两个关键组件:Apache Struts和Dozer。Apache Struts是一种广泛使用的开源MVC(Model-View-Controller)框架,它为Java Web应用程序提供了一种组织代码和控制应用...
下面将详细介绍Struts Token的工作原理、实现方式及其重要性。 一、工作原理 Struts Token机制的核心思想是在客户端(浏览器)和服务器端(应用服务器)之间维持一个唯一的令牌(Token)。当用户首次提交表单时,...
下面将详细解释Struts Token的工作原理、应用场景以及如何在实际项目中实现。 Token机制的核心思想是在用户发起敏感操作时,服务器生成一个随机的、一次性使用的Token,并将其存储在服务器端和客户端(通常为...
- **内置拦截器**:Struts2提供了一系列内置拦截器,如`params`(参数填充)、`token`(防止重复提交)、`servletConfig`(获取Servlet配置信息)等。 - **自定义拦截器**:可以通过实现`Interceptor`接口或继承`...
- **org.apache.struts2.components**:封装视图组件,Struts2在视图组件上做了很大加强,新增了多个组件,如`updownselect`、`doubleselect`、`datetimepicker`、`token`、`tree`等。 - **org.apache.struts2....
Struts 1.2 是一个经典的Java Web框架,它在早期Web开发中广泛使用。本话题将探讨如何在Struts 1.2中利用Token机制来解决HTTP请求的...同时,深入研究源码有助于加深对Struts工作原理的理解,提升问题排查和优化能力。
1. **配置Struts2拦截器**:在struts.xml配置文件中,需要添加`token`和`tokenSession`拦截器到默认栈或自定义的拦截器栈中。`token`拦截器负责在表单中插入令牌,而`tokenSession`拦截器则负责验证令牌。 ```xml ...
在深入理解Struts2的工作原理时,源码分析是必不可少的步骤。Struts2的核心设计理念和设计模式相比Struts1.x有了显著的变化,这使得它成为一个独立且成熟的框架。 首先,Struts2的架构基于WebWork的核心,这意味着...
#### 二、Token机制的原理 为了解决这一问题,一种常见的做法是在客户端(通常是浏览器)和服务器端之间传递一个随机生成的唯一标识符(Token)。当用户首次提交表单时,服务器会验证该Token是否有效。如果Token...