1、原理

服务器端和客户端通过token(令牌)来进行验证:

(1)Browser向Tomcat服务器请求填写表单

(2)Tomcat服务器将带有token的表单返回给Browser

(3)浏览器端在提交时,将form和token一起发送到服务器

(4)Tomcat服务器对Browser进行验证


2、基本步骤

基本步骤如下:

第一步:写好Action,在struts.xml为接受该表单提交请求的action配置token拦截器【服务器】

<action name="student_*" class="com.rupeng.action.StudentAction" method="{1}">
	<interceptor-ref name="defaultStack"/>
	<!-- 增加token拦截器 -->
	<interceptor-ref name="token">
		<!-- 定义被token拦截器拦截的方法 -->
		<param name=“includeMethods">add</param>
	</interceptor-ref>    
	<!-- 当表单重复提交时转向的页面 -->
	<result name="invalid.token">/WEB-INF/page/resubmitError.jsp</result>  	
</action>

第二步:在form中使用标签token【浏览器】

<s:form action="student_add" method="post" namespace="/test">
	<s:textfield name="name/><br>
	<s:textfield name="degree/><br>
	<s:token/><s:submit/>
</s:form>


第三步:处理错误【浏览器】

     使用<s:actionerror>在出错处理页面中提示错误信息,

     在配置中加入了“token”拦截器和“invalid.token”结果,当“token”拦截器发现会话token与请求token不一致时,将直接返回“invalid.token”结果。


3、示例

(1)Action类:StudentAction.java

package com.rk.strut.h_token;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionSupport;

public class StudentAction extends ActionSupport
{
	private String username;
	private String password;
	public String getUsername()
	{
		return username;
	}
	public void setUsername(String username)
	{
		this.username = username;
	}
	public String getPassword()
	{
		return password;
	}
	public void setPassword(String password)
	{
		this.password = password;
	}
	
	public String add()
	{
		HttpServletRequest request = ServletActionContext.getRequest();
		request.setAttribute("user", username);
		request.setAttribute("pwd", password);
		return "success";
	}
}

(2)进行配置struts-token.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
	"http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>
	<package name="rk_token" namespace="/rk/token" extends="struts-default">
		<action name="add" class="com.rk.strut.h_token.StudentAction" method="add">
			<interceptor-ref name="token"></interceptor-ref>
			<result name="success">/token/success.jsp</result>
			<result name="invalid.token">/token/invalid.jsp</result>
		</action>
	</package>
</struts>

struts-token.xml添加到struts.xml中

<include file="com/rk/strut/h_token/struts-token.xml"></include>

(3)前台表单页面add.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>添加学生</title>
</head>
<body>
	<form action="${pageContext.request.contextPath }/rk/token/add" method="post">
		用户名:<input type="text" name="username"/><br/>
		密码:<input type="password" name="password"/><br/>
		<input type="submit" value="提交"/>
		<s:token></s:token>
	</form>
</body>
</html>



(4)错误处理页面

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
 <%@taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>token无效</title>
</head>
<body>
	<s:actionerror/>
</body>
</html>


可以看一下<s:token>标签生成的html代码

Struts2系列:(13)防表单重复提交(token + 拦截器)_struts




4、补充

服务器端和客户端通过token(令牌)来进行验证:

(1)Browser向Tomcat服务器请求填写表单

(2)Tomcat服务器将带有token的表单返回给Browser

(3)浏览器端在提交时,将form和token一起发送到服务器

(4)Tomcat服务器对Browser进行验证


token拦截器定义在名为struts-default的package内。

struts-default.xml

<interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/>


org.apache.struts2.interceptor.TokenInterceptor


(1)举例

This interceptor can make sure that back buttons and double clicks don't cause un-intended side affects. For example, you can use this to prevent careless users who might double click on a "checkout" button at an online store. 

(2)服务器端实现机制

This interceptor uses a fairly primitive technique for when an invalid token is found: it returns the result invalid.token【返回invalid.token】, which can be mapped in your action configuration. A more complex implementation, TokenSessionStoreInterceptor【更复杂的实现TokenSessionStoreInterceptor】, can provide much better logic for when invalid tokens are found. 

(3)浏览器端必须使用token tag

To set a token in your form, you should use the token tag【在JSP的form中应该使用token tag】. This tag is required and must be used in the forms that submit to actions protected by this interceptor. 

(4)注意

Any request that does not provide a token (using the token tag) will be processed as a request with an invalid token. 

如果浏览器端不带有token信息,将被视为无效的token。


(5)示例代码

Example code: 

 <action name="someAction" class="com.examples.SomeAction">
     <interceptor-ref name="token"/>
     <interceptor-ref name="basicStack"/>
     <result name="success">good_result.ftl</result>
 </action>
 <-- In this case, myMethod of the action class will not
        get checked for invalidity of token -->
 <action name="someAction" class="com.examples.SomeAction">
     <interceptor-ref name="token">
        <param name="excludeMethods">myMethod</param>
     </interceptor-ref name="token"/>
     <interceptor-ref name="basicStack"/>
     <result name="success">good_result.ftl</result>
 </action>