欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot接口加密解密統(tǒng)一處理

 更新時(shí)間:2019年08月15日 08:33:32   作者:恒奇恒毅  
這篇文章主要為大家詳細(xì)介紹了SpringBoot接口加密解密統(tǒng)一處理,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

我們與客戶(hù)端的接口交互中,為了更高的安全性,我們可能需要對(duì)接口加密(請(qǐng)求參數(shù)加密,服務(wù)端解密)、返回信息加密(服務(wù)端加密,客戶(hù)端解密),但是也不是所有的接口都這樣,有些接口可能不需要,我們可以使用注解來(lái)輕松達(dá)到此要求。

將接口參數(shù)的加密解密和返回信息的加密解密分開(kāi),分別定義注解,利用Controller的ControllerAdvice來(lái)攔截所有的請(qǐng)求,在其中判斷是否需要加密解密,即可達(dá)到要求。

使用方法:使用 DecryptRequest 和 EncryptResponse 注解即可,可以放在Controller的類(lèi)和方法上,其中一個(gè)為false就不執(zhí)行了。像這樣:

@RestController
@RequestMapping("/test")
//@DecryptRequest
@EncryptResponse
public class TestController {
  @Autowired
  @Qualifier("rrCrypto")
  private Crypto crypto;
 
  @DecryptRequest(false)
  @EncryptResponse(false)
  @RequestMapping(value = "/enc" , method = RequestMethod.POST)
  public String enc(@RequestBody String body){
    return crypto.encrypt(body);
  }
}

定義參數(shù)解密的注解,DecryptRequest。

/**
 * 解密注解
 * 
 * <p>加了此注解的接口(true)將進(jìn)行數(shù)據(jù)解密操作(post的body) 可
 *  以放在類(lèi)上,可以放在方法上 </p>
 * @author xiongshiyan
 */
@Target({ElementType.METHOD , ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DecryptRequest {
  /**
   * 是否對(duì)body進(jìn)行解密
   */
  boolean value() default true;
}

定義返回信息加密的注解,EncryptResponse。

/**
 * 加密注解
 *
 * <p>加了此注解的接口(true)將進(jìn)行數(shù)據(jù)加密操作
 *  可以放在類(lèi)上,可以放在方法上 </p>
 * @author 熊詩(shī)言
 */
@Target({ElementType.METHOD , ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EncryptResponse {
  /**
   * 是否對(duì)結(jié)果加密
   */
  boolean value() default true;
}

這兩個(gè)注解可以放在類(lèi)和方法上,遵循一樣的邏輯,即:類(lèi)上的注解 && 方法上的注解,一方?jīng)]有即為true,都為false為false。邏輯主要在 NeedCrypto 中。

/**
 * 判斷是否需要加解密
 * @author xiongshiyan at 2018/8/30 , contact me with email yanshixiong@126.com or phone 15208384257
 */
class NeedCrypto {
  private NeedCrypto(){}
  /**
   * 是否需要對(duì)結(jié)果加密
   * 1.類(lèi)上標(biāo)注或者方法上標(biāo)注,并且都為true
   * 2.有一個(gè)標(biāo)注為false就不需要加密
   */
  static boolean needEncrypt(MethodParameter returnType) {
    boolean encrypt = false;
    boolean classPresentAnno = returnType.getContainingClass().isAnnotationPresent(EncryptResponse.class);
    boolean methodPresentAnno = returnType.getMethod().isAnnotationPresent(EncryptResponse.class);
 
    if(classPresentAnno){
      //類(lèi)上標(biāo)注的是否需要加密
      encrypt = returnType.getContainingClass().getAnnotation(EncryptResponse.class).value();
      //類(lèi)不加密,所有都不加密
      if(!encrypt){
        return false;
      }
    }
    if(methodPresentAnno){
      //方法上標(biāo)注的是否需要加密
      encrypt = returnType.getMethod().getAnnotation(EncryptResponse.class).value();
    }
    return encrypt;
  }
  /**
   * 是否需要參數(shù)解密
   * 1.類(lèi)上標(biāo)注或者方法上標(biāo)注,并且都為true
   * 2.有一個(gè)標(biāo)注為false就不需要解密
   */
  static boolean needDecrypt(MethodParameter parameter) {
    boolean encrypt = false;
    boolean classPresentAnno = parameter.getContainingClass().isAnnotationPresent(DecryptRequest.class);
    boolean methodPresentAnno = parameter.getMethod().isAnnotationPresent(DecryptRequest.class);
 
    if(classPresentAnno){
      //類(lèi)上標(biāo)注的是否需要解密
      encrypt = parameter.getContainingClass().getAnnotation(DecryptRequest.class).value();
      //類(lèi)不加密,所有都不加密
      if(!encrypt){
        return false;
      }
    }
    if(methodPresentAnno){
      //方法上標(biāo)注的是否需要解密
      encrypt = parameter.getMethod().getAnnotation(DecryptRequest.class).value();
    }
    return encrypt;
  }
}

然后定義ControllerAdvice,對(duì)于請(qǐng)求解密的,定義 DecryptRequestBodyAdvice ,實(shí)現(xiàn) RequestBodyAdvice 。

/**
 * 請(qǐng)求數(shù)據(jù)接收處理類(lèi)<br>
 * 
 * 對(duì)加了@Decrypt的方法的數(shù)據(jù)進(jìn)行解密操作<br>
 * 
 * 只對(duì) @RequestBody 參數(shù)有效
 * @author xiongshiyan
 */
@ControllerAdvice
@ConditionalOnProperty(prefix = "spring.crypto.request.decrypt", name = "enabled" , havingValue = "true", matchIfMissing = true)
public class DecryptRequestBodyAdvice implements RequestBodyAdvice {
 
  @Value("${spring.crypto.request.decrypt.charset:UTF-8}")
  private String charset = "UTF-8";
 
  @Autowired
  @Qualifier("rrCrypto")
  private Crypto crypto;
 
 @Override
 public boolean supports(MethodParameter methodParameter, Type targetType,
  Class<? extends HttpMessageConverter<?>> converterType) {
 return true;
 }
 
 @Override
 public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter,
  Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
 return body;
 }
 
 @Override
 public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
  Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
 if( NeedCrypto.needDecrypt(parameter) ){
      return new DecryptHttpInputMessage(inputMessage , charset , crypto);
 }
 return inputMessage;
 }
 
 @Override
 public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
  Class<? extends HttpMessageConverter<?>> converterType) {
 return body;
 }
}

標(biāo)上注解 ConditionalOnProperty 表示只有條件為true的時(shí)候才開(kāi)啟解密功能,一個(gè)配置即可打開(kāi)或者關(guān)閉解密功能。真正的解密邏輯留給 DecryptHttpInputMessage , 它又委托給 Crypto。

/**
 *
 * @author xiongshiyan
 */
public class DecryptHttpInputMessage implements HttpInputMessage {
  private HttpInputMessage inputMessage;
  private String charset;
  private Crypto crypto;
 
  public DecryptHttpInputMessage(HttpInputMessage inputMessage, String charset , Crypto crypto) {
    this.inputMessage = inputMessage;
    this.charset = charset;
    this.crypto = crypto;
  }
 
  @Override
  public InputStream getBody() throws IOException {
    String content = IoUtil.read(inputMessage.getBody() , charset);
 
    String decryptBody = crypto.decrypt(content, charset);
 
    return new ByteArrayInputStream(decryptBody.getBytes(charset));
  }
 
  @Override
  public HttpHeaders getHeaders() {
    return inputMessage.getHeaders();
  }
}

對(duì)于返回值加密,定義 EncryptResponseBodyAdvice,實(shí)現(xiàn) ResponseBodyAdvice。

/**
 * 請(qǐng)求響應(yīng)處理類(lèi)<br>
 * 
 * 對(duì)加了@Encrypt的方法的數(shù)據(jù)進(jìn)行加密操作
 * 
 * @author 熊詩(shī)言
 *
 */
@ControllerAdvice
@ConditionalOnProperty(prefix = "spring.crypto.response.encrypt", name = "enabled" , havingValue = "true", matchIfMissing = true)
public class EncryptResponseBodyAdvice implements ResponseBodyAdvice<Object> {
 
  @Value("${spring.crypto.request.decrypt.charset:UTF-8}")
  private String charset = "UTF-8";
 
  @Autowired
  @Qualifier("rrCrypto")
  private Crypto crypto;
 
 @Override
 public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
 return true;
 }
 
 @Override
 public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
  Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
    boolean encrypt = NeedCrypto.needEncrypt(returnType);
 
    if( !encrypt ){
      return body;
    }
 
    if(!(body instanceof ResponseMsg)){
      return body;
    }
 
    //只針對(duì)ResponseMsg的data進(jìn)行加密
    ResponseMsg responseMsg = (ResponseMsg) body;
    Object data = responseMsg.getData();
    if(null == data){
      return body;
    }
 
    String xx;
    Class<?> dataClass = data.getClass();
    if(dataClass.isPrimitive() || (data instanceof String)){
      xx = String.valueOf(data);
    }else {
      //JavaBean、Map、List等先序列化
      if(List.class.isAssignableFrom(dataClass)){
        xx = JsonUtil.serializeList((List<Object>) data);
      }else if(Map.class.isAssignableFrom(dataClass)){
        xx = JsonUtil.serializeMap((Map<String, Object>) data);
      }else {
        xx = JsonUtil.serializeJavaBean(data);
      }
    }
    
    responseMsg.setData(crypto.encrypt(xx, charset));
 
    return responseMsg;
 }
 
}

真正的加密邏輯委托給 Crypto ,這是一個(gè)加密解密的接口,有很多實(shí)現(xiàn)類(lèi),參見(jiàn):鏈接

/**
 * Request-Response加解密體系的加解密方式
 * @author xiongshiyan at 2018/8/14 , contact me with email yanshixiong@126.com or phone 15208384257
 */
@Configuration
public class RRCryptoConfig {
  /**
   * 加密解密方式使用一樣的
   */
  @Bean("rrCrypto")
  public Crypto rrCrypto(){
    return new AesCrypto("密鑰key");
  }
}

至此,一個(gè)完美的對(duì)接口的加密解密就實(shí)現(xiàn)了。

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

相關(guān)文章

  • Java解析變量公式的簡(jiǎn)單示例

    Java解析變量公式的簡(jiǎn)單示例

    在Java編程中,經(jīng)常會(huì)遇到需要解析表達(dá)式或公式的情況,特別是涉及到動(dòng)態(tài)計(jì)算或配置項(xiàng)的場(chǎng)景,在本篇文章中,我將介紹如何在Java中解析變量公式,并給出一個(gè)簡(jiǎn)單的實(shí)現(xiàn)示例,需要的朋友可以參考下
    2024-10-10
  • Java并發(fā)程序刺客之假共享的原理及復(fù)現(xiàn)

    Java并發(fā)程序刺客之假共享的原理及復(fù)現(xiàn)

    前段時(shí)間在各種社交平臺(tái)“雪糕刺客”這個(gè)詞比較火,而在并發(fā)程序中也有一個(gè)刺客,那就是假共享。本文將通過(guò)示例詳細(xì)講解假共享的原理及復(fù)現(xiàn),需要的可以參考一下
    2022-08-08
  • java后臺(tái)如何接收get請(qǐng)求傳過(guò)來(lái)的數(shù)組

    java后臺(tái)如何接收get請(qǐng)求傳過(guò)來(lái)的數(shù)組

    這篇文章主要介紹了java后臺(tái)如何接收get請(qǐng)求傳過(guò)來(lái)的數(shù)組問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • IDEA+Maven創(chuàng)建Spring項(xiàng)目的實(shí)現(xiàn)步驟

    IDEA+Maven創(chuàng)建Spring項(xiàng)目的實(shí)現(xiàn)步驟

    這篇文章主要介紹了IDEA+Maven創(chuàng)建Spring項(xiàng)目的實(shí)現(xiàn)步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • Mybatis中foreach標(biāo)簽帶來(lái)的空格\換行\(zhòng)回車(chē)問(wèn)題及解決方案

    Mybatis中foreach標(biāo)簽帶來(lái)的空格\換行\(zhòng)回車(chē)問(wèn)題及解決方案

    這篇文章主要介紹了解決Mybatis中foreach標(biāo)簽帶來(lái)的空格,換行,回車(chē)問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-04-04
  • Java中FileWriter的用法及wirte()重載方法詳解

    Java中FileWriter的用法及wirte()重載方法詳解

    這篇文章主要介紹了Java中FileWriter的用法及wirte()重載方法詳解,FileWriter是Java編程語(yǔ)言中的一個(gè)類(lèi),用于將字符寫(xiě)入文件,它提供了一種簡(jiǎn)單而方便的方式來(lái)創(chuàng)建、打開(kāi)和寫(xiě)入文件,通過(guò)使用FileWriter,我們可以將字符數(shù)據(jù)寫(xiě)入文本文件,需要的朋友可以參考下
    2023-10-10
  • 基于SpringBoot制作一個(gè)PDF切圖小工具

    基于SpringBoot制作一個(gè)PDF切圖小工具

    這篇文章主要為大家詳細(xì)介紹了如何基于SpringBoot制作一個(gè)PDF切圖小工具,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-01-01
  • Java解壓zip文件的關(guān)鍵代碼

    Java解壓zip文件的關(guān)鍵代碼

    本文給大家分享一段java解壓zip文件的關(guān)鍵代碼,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有參考借鑒價(jià)值,感興趣的朋友一起看看吧
    2016-09-09
  • java秒殺之redis限流操作詳解

    java秒殺之redis限流操作詳解

    這篇文章主要為大家詳細(xì)介紹了java秒殺之redis限流操作,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • 淺析Java中的虛擬線(xiàn)程

    淺析Java中的虛擬線(xiàn)程

    在本篇文章中,小編將帶大家深入了解Java虛擬線(xiàn)程的原理、如何使用、使用的注意事項(xiàng)以及其他相似技術(shù)的差別,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-10-10

最新評(píng)論