亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Spring MVC接口防數(shù)據(jù)篡改和重復(fù)提交

 更新時(shí)間:2019年08月06日 09:51:59   作者:一代鍵客  
這篇文章主要為大家詳細(xì)介紹了Spring MVC接口防數(shù)據(jù)篡改和重復(fù)提交,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

本文實(shí)例為大家分享了Spring MVC接口防數(shù)據(jù)篡改和重復(fù)提交的具體代碼,供大家參考,具體內(nèi)容如下

一、自定義一個(gè)注解,此注解可以使用在方法上或類上

  • 使用在方法上,表示此方法需要數(shù)據(jù)校驗(yàn)
  • 使用在類上,表示此類下的所有方法需要數(shù)據(jù)校驗(yàn)
  • 此注解對(duì)無(wú)參數(shù)方法不起作用
import org.springframework.stereotype.Component;
 
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface DataValidate {
 
}

二、自定義攔截,攔截前端所有請(qǐng)求

1、檢查此接口調(diào)用的方法或方法所在的類是否使用了DataValidate注解,若沒(méi)有使用,表示此接口不需要校驗(yàn)數(shù)據(jù);
2、若使用了注解,再檢查此方法有沒(méi)有入?yún)?,若沒(méi)有入?yún)ⅲ恍枰r?yàn)數(shù)據(jù),否在需要校驗(yàn);
3、把前端傳來(lái)的所有參數(shù) (除了簽名參數(shù))按照參數(shù)升序生成一個(gè)json字符串(使用TreeMap方式自動(dòng)排序);
4、把生成的json字符串通過(guò)MD5加密的結(jié)果和前端傳的簽名值對(duì)比,若不相等,表示此數(shù)據(jù)被篡改過(guò),否在沒(méi)有被篡改過(guò);
5、數(shù)據(jù)是否被篡改校驗(yàn)完畢,若前端傳了用戶唯一標(biāo)示(token),表示需要校驗(yàn)數(shù)據(jù)是否重復(fù)提交;
6、若簽名和上次提交的數(shù)據(jù)的簽名相等,表示是重復(fù)提交數(shù)據(jù),若不相等,把簽名保存下來(lái),表示數(shù)據(jù)不是重復(fù)提交。

import java.security.MessageDigest;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
 
import javax.annotation.PreDestroy;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.MethodParameter;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
 
import com.alibaba.fastjson.JSON;
 
/**
 * 防數(shù)據(jù)被篡改和重復(fù)提交
 */
 
public class DataValidateInterceptor extends HandlerInterceptorAdapter implements Runnable {
 
 public static Map<String, TokenValue> userToken = new ConcurrentHashMap<>();
 
 // 過(guò)期時(shí)間
 private static long EXPIRED_TIME = 3600000;
 
 private static String TOKEN_NAME = "token";
 
 private static String SIGN_NAME = "sign";
 
 private volatile boolean shutDown;
 
 public DataValidateInterceptor(@Value("${data_interceptor.expired_time}") String expiredTime,
 @Value("${data_interceptor.token_name}") String tokenName,
 @Value("${data_interceptor.sign_name}") String signName) {
 if (null != expiredTime && !"".equals(expiredTime)) {
 EXPIRED_TIME = Long.parseLong(expiredTime);
 }
 if (null != tokenName && !"".equals(tokenName)) {
 TOKEN_NAME = tokenName;
 }
 if (null != signName && !"".equals(signName)) {
 SIGN_NAME = signName;
 }
 }
 
 @Override
 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
 throws Exception {
 if (validate(request, response, handler)) {
 /**
 * 實(shí)現(xiàn)返回提示數(shù)據(jù)
 */
 response.setContentType("application/json");
 response.setCharacterEncoding("UTF-8");
 response.getWriter().write("參數(shù)驗(yàn)證失敗!");
 return false;
 }
 return true;
 }
 
 private boolean validate(HttpServletRequest request, HttpServletResponse response, Object handler) {
 
 if (handler instanceof HandlerMethod) {
 Class<?> clazz = ((HandlerMethod) handler).getBeanType();
 DataValidate dataValidate = clazz.getAnnotation(DataValidate.class);
 if (null == dataValidate) {
 dataValidate = ((HandlerMethod) handler).getMethodAnnotation(DataValidate.class);
 }
 
 if (dataValidate != null) {
 MethodParameter[] methodParameters = ((HandlerMethod) handler).getMethodParameters();
 if (null == methodParameters || methodParameters.length <=0) {
  // 方法沒(méi)有入?yún)⒉恍枰r?yàn)
  return false;
 }
 
 // 需要校驗(yàn)
 String sign = request.getParameter(SIGN_NAME);
 Map<String, String[]> params = request.getParameterMap();
 Set<String> paramNames = params.keySet();
 Map<String, String> paramsMap = new TreeMap<>();
 for (String paramName : paramNames) {
  if (paramName.equals(SIGN_NAME)) {
  continue;
  }
  paramsMap.put(paramName, request.getParameter(paramName));
 }
 String paramString = JSON.toJSONString(paramsMap).replaceAll(" ", "");
 String MD5Sign = MD5.getMD5(paramString);
 if (!sign.equals(MD5Sign)) {
  // 數(shù)據(jù)被篡改
  return true;
 }
 
 String token = request.getParameter(TOKEN_NAME);
 if (token != null) {
  if (userToken.containsKey(token)) {
  TokenValue tokenValue = userToken.get(token);
  if (tokenValue.getValue().equals(sign)) {
  // 數(shù)據(jù)已經(jīng)提交過(guò)
  return true;
  } else {
  tokenValue.setValue(sign);
  }
  } else {
  userToken.put(token, new TokenValue(sign));
  }
 }
 
 }
 }
 return false;
 }
 
 @Override
 public void run() {
 try {
 while (!shutDown) {
 synchronized (this) {
  wait(EXPIRED_TIME);
  Set<String> keys = userToken.keySet();
  for (String key : keys) {
  if ((userToken.get(key).getExpiredTime() + EXPIRED_TIME) <= System.currentTimeMillis()) {
  userToken.remove(key);
  }
  }
 }
 }
 } catch (Exception e) {
 e.printStackTrace();
 }
 }
 
 @PreDestroy
 public void custDestroy() {
 shutDown = true;
 synchronized (this) {
 notifyAll();
 }
 }
 
 private static class MD5 {
 
 /**
  * 向getMD5方法傳入一個(gè)你需要轉(zhuǎn)換的原始字符串,將返回字符串的MD5碼
  * 
  * @param code 原始字符串
  * @return 返回字符串的MD5碼
  */
  private static String getMD5(String code) {
   try {
    MessageDigest messageDigest = MessageDigest.getInstance("MD5");
 
    byte[] bytes = code.getBytes();
 
    byte[] results = messageDigest.digest(bytes);
 
    StringBuilder stringBuilder = new StringBuilder();
 
    for (byte result : results) {
     // 將byte數(shù)組轉(zhuǎn)化為16進(jìn)制字符存入stringbuilder中
     stringBuilder.append(String.format("%02x", result));
    }
 
    return stringBuilder.toString();
   } catch (Exception e) {
    e.printStackTrace();
    return "";
   }
  }
 }
 
}
 
public class TokenValue {
 
 private String value;
 private long expiredTime;
 
 public TokenValue(String value) {
 this.value = value;
 this.expiredTime = System.currentTimeMillis();
 }
 
 public String getValue() {
 return value;
 }
 public void setValue(String value) {
 this.value = value;
 this.expiredTime = System.currentTimeMillis();
 }
 public long getExpiredTime() {
 return expiredTime;
 }
}

三、使用

后端使用:

1.在需要數(shù)據(jù)校驗(yàn)的方法或類上使用DataValidate注解(若在類上使用,表示此類下的所有方法需要驗(yàn)證)

2.配置 DataValidateInterceptor 攔截器

3.配置前端簽名參數(shù),默認(rèn)是sign

4.配置用戶唯一標(biāo)示參數(shù),默認(rèn)是token(防止數(shù)據(jù)重復(fù)提交需要)

5.配置用戶唯一標(biāo)示過(guò)期時(shí)間,默認(rèn)是1h,單位是ms(防止數(shù)據(jù)重復(fù)提交需要)

前端使用:

1.獲取用戶唯一標(biāo)示(防止數(shù)據(jù)重復(fù)提交需要)

2.把需要提交的數(shù)據(jù)根據(jù)參數(shù)(包括用戶唯一標(biāo)示)升序排序然后生成一個(gè)json字符串(不能有空格),最后把json字符串進(jìn)行MD5加密生成32位小寫(xiě)加密結(jié)果簽名

eg:需要提交的數(shù)據(jù)為{messageType: "userQueryWait", companyCode: "test_app", token:"123213213"},排序后生成json字符串 {"companyCode":"test_app","messageType":"userQueryWait","token":"123213213"}, md5生成簽名

3.把簽名和需要提交的數(shù)據(jù)一起傳到后臺(tái)

eg:{messageType: "userQueryWait", companyCode: "test_app", token:"123213213", sign:"719bdb1fb769efb68e40440d1628ed5b"}

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

相關(guān)文章

  • 淺談java 單例模式DCL的缺陷及單例的正確寫(xiě)法

    淺談java 單例模式DCL的缺陷及單例的正確寫(xiě)法

    這篇文章主要介紹了淺談java 單例模式DCL的缺陷及單例的正確寫(xiě)法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-09-09
  • 兼容Spring Boot 1.x和2.x配置類參數(shù)綁定的工具類SpringBootBindUtil

    兼容Spring Boot 1.x和2.x配置類參數(shù)綁定的工具類SpringBootBindUtil

    今天小編就為大家分享一篇關(guān)于兼容Spring Boot 1.x和2.x配置類參數(shù)綁定的工具類SpringBootBindUtil,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-12-12
  • SpringBoot框架實(shí)現(xiàn)切換啟動(dòng)開(kāi)發(fā)環(huán)境和測(cè)試環(huán)境

    SpringBoot框架實(shí)現(xiàn)切換啟動(dòng)開(kāi)發(fā)環(huán)境和測(cè)試環(huán)境

    這篇文章主要介紹了SpringBoot框架實(shí)現(xiàn)切換啟動(dòng)開(kāi)發(fā)環(huán)境和測(cè)試環(huán)境,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • JavaMail郵件簡(jiǎn)介及API概述第一篇

    JavaMail郵件簡(jiǎn)介及API概述第一篇

    這篇文章主要為大家詳細(xì)介紹了JavaMail郵件簡(jiǎn)介及API概述第一篇,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • Java BeanDefination接口詳細(xì)講解

    Java BeanDefination接口詳細(xì)講解

    BeanDefinition是spring里面bean的一個(gè)建模對(duì)象,就相當(dāng)于class對(duì)象是普通java對(duì)象的建模對(duì)象一樣??赡茉趕pring作用的各種業(yè)務(wù)場(chǎng)景中,class對(duì)象并不能完成spring對(duì)bean的抽象,所以弄了一個(gè)BeanDefinition作為bean的抽象建模對(duì)象
    2022-11-11
  • java集合框架線程同步代碼詳解

    java集合框架線程同步代碼詳解

    這篇文章主要介紹了java集合框架線程同步代碼詳解,具有一定借鑒價(jià)值,需要的朋友可以參考下。
    2017-12-12
  • JDK12的新特性之CompactNumberFormat詳解

    JDK12的新特性之CompactNumberFormat詳解

    這篇文章主要介紹了JDK12的新特性之CompactNumberFormat,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-05-05
  • 詳解JAVA的控制語(yǔ)句

    詳解JAVA的控制語(yǔ)句

    這篇文章主要介紹了Java中的控制語(yǔ)句,循環(huán)等語(yǔ)句是Java編程中流程控制的基礎(chǔ),需要的朋友可以參考下,希望能夠給你帶來(lái)幫助
    2021-11-11
  • MyBatis-Plus結(jié)合Layui實(shí)現(xiàn)分頁(yè)方法

    MyBatis-Plus結(jié)合Layui實(shí)現(xiàn)分頁(yè)方法

    MyBatis-Plus 使用簡(jiǎn)單,本文主要介紹使用 service 中的 page 方法結(jié)合 Layui 前端框架實(shí)現(xiàn)分頁(yè)效果,具有一定的參考價(jià)值,感興趣的可以了解一下
    2021-08-08
  • Java內(nèi)部類的繼承(全)

    Java內(nèi)部類的繼承(全)

    這篇文章主要介紹了Java內(nèi)部類的繼承,大家都知道JAVA內(nèi)部類的構(gòu)造器必須連接指向其外圍類對(duì)象的引用,所以在繼承內(nèi)部類的時(shí)候,需要在導(dǎo)出類的構(gòu)造器中手動(dòng)加入對(duì)基類構(gòu)造器的調(diào)用,需要的朋友可以參考下
    2015-07-07

最新評(píng)論