一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專(zhuān)注于服務(wù)器技術(shù)及軟件下載分享
分類(lèi)導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語(yǔ)言|JavaScript|易語(yǔ)言|vb.net|

服務(wù)器之家 - 編程語(yǔ)言 - Java教程 - springMVC中基于token防止表單重復(fù)提交方法

springMVC中基于token防止表單重復(fù)提交方法

2020-12-06 14:58qq_641041990 Java教程

本篇文章主要介紹了springMVC中基于token防止表單重復(fù)提交方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

本文介紹了springMVC中基于token防止表單重復(fù)提交方法,分享給大家,具體如下:

實(shí)現(xiàn)思路:

在springmvc配置文件中加入攔截器的配置,攔截兩類(lèi)請(qǐng)求,一類(lèi)是到頁(yè)面的,一類(lèi)是提交表單的。當(dāng)轉(zhuǎn)到頁(yè)面的請(qǐng)求到來(lái)時(shí),生成token的名字和token值,一份放到Redis緩存中,一份放傳給頁(yè)面表單的隱藏域。(注:這里之所以使用redis緩存,是因?yàn)閠omcat服務(wù)器是集群部署的,要保證token的存儲(chǔ)介質(zhì)是全局線程安全的,而redis是單線程的)

當(dāng)表單請(qǐng)求提交時(shí),攔截器得到參數(shù)中的tokenName和token,然后到緩存中去取token值,如果能匹配上,請(qǐng)求就通過(guò),不能匹配上就不通過(guò)。這里的tokenName生成時(shí)也是隨機(jī)的,每次請(qǐng)求都不一樣。而從緩存中取token值時(shí),會(huì)立即將其刪除(刪與讀是原子的,無(wú)線程安全問(wèn)題)。

實(shí)現(xiàn)方式:

TokenInterceptor.Java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package com.xxx.www.common.interceptor;
 
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import com.xxx.cache.redis.IRedisCacheClient;
import com.xxx.common.utility.JsonUtil;
import com.xxx.www.common.utils.TokenHelper;
 
/**
 *
 * @see TokenHelper
 */
public class TokenInterceptor extends HandlerInterceptorAdapter
{
 
  private static Logger log = Logger.getLogger(TokenInterceptor.class);
  private static Map<String , String> viewUrls = new HashMap<String , String>();
  private static Map<String , String> actionUrls = new HashMap<String , String>();
  private Object clock = new Object();
 
  @Autowired
  private IRedisCacheClient redisCacheClient;
  static
  {
    viewUrls.put("/user/regc/brandregnamecard/", "GET");
    viewUrls.put("/user/regc/regnamecard/", "GET");
 
    actionUrls.put("/user/regc/brandregnamecard/", "POST");
    actionUrls.put("/user/regc/regnamecard/", "POST");
  }
  {
    TokenHelper.setRedisCacheClient(redisCacheClient);
  }
 
  /**
   * 攔截方法,添加or驗(yàn)證token
   */
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
  {
    String url = request.getRequestURI();
    String method = request.getMethod();
    if(viewUrls.keySet().contains(url) && ((viewUrls.get(url)) == null || viewUrls.get(url).equals(method)))
    {
      TokenHelper.setToken(request);
      return true;
    }
    else if(actionUrls.keySet().contains(url) && ((actionUrls.get(url)) == null || actionUrls.get(url).equals(method)))
    {
      log.debug("Intercepting invocation to check for valid transaction token.");
      return handleToken(request, response, handler);
    }
    return true;
  }
 
  protected boolean handleToken(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
  {
    synchronized(clock)
    {
      if(!TokenHelper.validToken(request))
      {
        System.out.println("未通過(guò)驗(yàn)證...");
        return handleInvalidToken(request, response, handler);
      }
    }
    System.out.println("通過(guò)驗(yàn)證...");
    return handleValidToken(request, response, handler);
  }
 
  /**
   * 當(dāng)出現(xiàn)一個(gè)非法令牌時(shí)調(diào)用
   */
  protected boolean handleInvalidToken(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
  {
    Map<String , Object> data = new HashMap<String , Object>();
    data.put("flag", 0);
    data.put("msg", "請(qǐng)不要頻繁操作!");
    writeMessageUtf8(response, data);
    return false;
  }
 
  /**
   * 當(dāng)發(fā)現(xiàn)一個(gè)合法令牌時(shí)調(diào)用.
   */
  protected boolean handleValidToken(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
  {
    return true;
  }
 
  private void writeMessageUtf8(HttpServletResponse response, Map<String , Object> json) throws IOException
  {
    try
    {
      response.setCharacterEncoding("UTF-8");
      response.getWriter().print(JsonUtil.toJson(json));
    }
    finally
    {
      response.getWriter().close();
    }
  }
 
}

TokenHelper.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
package com.xxx.www.common.utils;
 
import java.math.BigInteger;
import java.util.Map;
import java.util.Random;
import javax.servlet.http.HttpServletRequest;
import org.apache.log4j.Logger;
import com.xxx.cache.redis.IRedisCacheClient;
 
/**
 * TokenHelper
 *
 */
public class TokenHelper
{
 
  /**
   * 保存token值的默認(rèn)命名空間
   */
  public static final String TOKEN_NAMESPACE = "xxx.tokens";
 
  /**
   * 持有token名稱(chēng)的字段名
   */
  public static final String TOKEN_NAME_FIELD = "xxx.token.name";
  private static final Logger LOG = Logger.getLogger(TokenHelper.class);
  private static final Random RANDOM = new Random();
 
  private static IRedisCacheClient redisCacheClient;// 緩存調(diào)用,代替session,支持分布式
 
  public static void setRedisCacheClient(IRedisCacheClient redisCacheClient)
  {
    TokenHelper.redisCacheClient = redisCacheClient;
  }
 
  /**
   * 使用隨機(jī)字串作為token名字保存token
   *
   * @param request
   * @return token
   */
  public static String setToken(HttpServletRequest request)
  {
    return setToken(request, generateGUID());
  }
 
  /**
   * 使用給定的字串作為token名字保存token
   *
   * @param request
   * @param tokenName
   * @return token
   */
  private static String setToken(HttpServletRequest request, String tokenName)
  {
    String token = generateGUID();
    setCacheToken(request, tokenName, token);
    return token;
  }
 
  /**
   * 保存一個(gè)給定名字和值的token
   *
   * @param request
   * @param tokenName
   * @param token
   */
  private static void setCacheToken(HttpServletRequest request, String tokenName, String token)
  {
    try
    {
      String tokenName0 = buildTokenCacheAttributeName(tokenName);
      redisCacheClient.listLpush(tokenName0, token);
      request.setAttribute(TOKEN_NAME_FIELD, tokenName);
      request.setAttribute(tokenName, token);
    }
    catch(IllegalStateException e)
    {
      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();
      LOG.error(msg, e);
      throw new IllegalArgumentException(msg);
    }
  }
 
  /**
   * 構(gòu)建一個(gè)基于token名字的帶有命名空間為前綴的token名字
   *
   * @param tokenName
   * @return the name space prefixed session token name
   */
  public static String buildTokenCacheAttributeName(String tokenName)
  {
    return TOKEN_NAMESPACE + "." + tokenName;
  }
 
  /**
   * 從請(qǐng)求域中獲取給定token名字的token值
   *
   * @param tokenName
   * @return the token String or null, if the token could not be found
   */
  public static String getToken(HttpServletRequest request, String tokenName)
  {
    if(tokenName == null)
    {
      return null;
    }
    Map params = request.getParameterMap();
    String[] tokens = (String[]) (String[]) params.get(tokenName);
    String token;
    if((tokens == null) || (tokens.length < 1))
    {
      LOG.warn("Could not find token mapped to token name " + tokenName);
      return null;
    }
 
    token = tokens[0];
    return token;
  }
 
  /**
   * 從請(qǐng)求參數(shù)中獲取token名字
   *
   * @return the token name found in the params, or null if it could not be found
   */
  public static String getTokenName(HttpServletRequest request)
  {
    Map params = request.getParameterMap();
 
    if(!params.containsKey(TOKEN_NAME_FIELD))
    {
      LOG.warn("Could not find token name in params.");
      return null;
    }
 
    String[] tokenNames = (String[]) params.get(TOKEN_NAME_FIELD);
    String tokenName;
 
    if((tokenNames == null) || (tokenNames.length < 1))
    {
      LOG.warn("Got a null or empty token name.");
      return null;
    }
 
    tokenName = tokenNames[0];
 
    return tokenName;
  }
 
  /**
   * 驗(yàn)證當(dāng)前請(qǐng)求參數(shù)中的token是否合法,如果合法的token出現(xiàn)就會(huì)刪除它,它不會(huì)再次成功合法的token
   *
   * @return 驗(yàn)證結(jié)果
   */
  public static boolean validToken(HttpServletRequest request)
  {
    String tokenName = getTokenName(request);
 
    if(tokenName == null)
    {
      LOG.debug("no token name found -> Invalid token ");
      return false;
    }
 
    String token = getToken(request, tokenName);
 
    if(token == null)
    {
      if(LOG.isDebugEnabled())
      {
        LOG.debug("no token found for token name " + tokenName + " -> Invalid token ");
      }
      return false;
    }
 
    String tokenCacheName = buildTokenCacheAttributeName(tokenName);
    String cacheToken = redisCacheClient.listLpop(tokenCacheName);
 
    if(!token.equals(cacheToken))
    {
      LOG.warn("xxx.internal.invalid.token Form token " + token + " does not match the session token " + cacheToken + ".");
      return false;
    }
 
    // remove the token so it won't be used again
 
    return true;
  }
 
  public static String generateGUID()
  {
    return new BigInteger(165,RANDOM).toString(36).toUpperCase();
  }
 
}

spring-mvc.xml

?
1
2
3
4
5
6
7
8
9
<!-- token攔截器-->
  <bean id="tokenInterceptor" class="com.xxx.www.common.interceptor.TokenInterceptor"></bean>  
  <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">  
    <property name="interceptors">  
      <list>  
        <ref bean="tokenInterceptor"/>  
      </list>
    </property>  
  </bean>

input.jsp 在form中加如下內(nèi)容:

?
1
2
3
<input type="hidden" name="<%=request.getAttribute("xxx.token.name") %>" value="<%=token %>"/>
 
<input type="hidden" name="xxx.token.name" value="<%=request.getAttribute("xxx.token.name") %>"/>

當(dāng)前這里也可以用類(lèi)似于struts2的自定義標(biāo)簽來(lái)做。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。

原文鏈接:http://blog.csdn.net/letter_believe/article/details/76034791

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产精品久久久久影院色老大 | 日韩免费在线观看 | 亚洲视频在线观看不卡 | 日日操美女 | 猛男强攻变sao货 | 好爽好紧小雪别夹小说 | 欧洲第一区第二区第三区 | 国产精品久久久久久久久99热 | 毛片的网站 | japanese在线看 | 青青青国产精品国产精品美女 | 青草久久网 | 国产精品亚洲午夜不卡 | 母性本能在线观看 | 韩国理论三级在线观看视频 | 欧美成人三级伦在线观看 | 国内外成人在线视频 | 国产一级持黄大片99久久 | 欧美xbxbxbbxxbb精品 | 皇上好大好硬好涨好深好爽 | 免费观看一级一片 | 国产二区视频 | 99免费在线视频 | www.亚洲色图 | 亚洲精品第三页 | sao虎在线精品永久在线 | 国产一区私人高清影院 | 奇米狠狠色 | 男人影院在线观看 | 2020国产精品永久在线观看 | 啊啊啊好大在线观看 | 好紧好爽的午夜寂寞视频 | 精品一区二区三区色花堂 | 特黄视频免费看 | 日韩在线天堂 | 五月天国产精品 | 久久久久久免费高清电影 | 情人梁家辉在线 | 99爱免费视频 | 亚洲精品色综合久久 | 无人区在线观看免费国语完整版 |