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

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(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教程 - Springboot 數(shù)據(jù)安全傳輸加密與解密

Springboot 數(shù)據(jù)安全傳輸加密與解密

2021-01-07 23:28今日頭條FastCoder Java教程

通過(guò)繼承RequestBodyAdviceAdapter實(shí)現(xiàn)對(duì)于請(qǐng)求的內(nèi)容進(jìn)行解密操作,實(shí)現(xiàn)ResponseBodyAdvice來(lái)對(duì)相應(yīng)內(nèi)容進(jìn)行加密處理。

Springboot 數(shù)據(jù)安全傳輸加密與解密

環(huán)境:springboot2.2.6.RELEASE、Vue+axios

通過(guò)繼承RequestBodyAdviceAdapter實(shí)現(xiàn)對(duì)于請(qǐng)求的內(nèi)容進(jìn)行解密操作,實(shí)現(xiàn)ResponseBodyAdvice來(lái)對(duì)相應(yīng)內(nèi)容進(jìn)行加密處理。

定義加密解密的接口:

SecretProcess.java

  1. public interface SecretProcess { 
  2.      
  3.     /** 
  4.      *  <p>數(shù)據(jù)加密</p> 
  5.      *  <p>時(shí)間:2020年12月24日-下午12:22:13</p> 
  6.      * @author xg 
  7.      * @param data 待加密數(shù)據(jù) 
  8.      * @return String 加密結(jié)果 
  9.      */ 
  10.     String encrypt(String data) ; 
  11.      
  12.     /** 
  13.      *  <p>數(shù)據(jù)解密</p> 
  14.      *  <p>時(shí)間:2020年12月24日-下午12:23:20</p> 
  15.      * @author xg 
  16.      * @param data 待解密數(shù)據(jù) 
  17.      * @return String 解密后的數(shù)據(jù) 
  18.      */ 
  19.     String decrypt(String data) ; 
  20.      
  21.     /** 
  22.      *  <p>加密算法格式:算法[/模式/填充]</p> 
  23.      *  <p>時(shí)間:2020年12月24日-下午12:32:49</p> 
  24.      * @author xg 
  25.      * @return String 
  26.      */ 
  27.     String getAlgorithm() ; 
  28.      
  29.     public static class Hex { 
  30.          
  31.         private static final char[] HEX = { '0''1''2''3''4''5''6''7''8''9'
  32.                 'a''b''c''d''e''f' }; 
  33.          
  34.         public static byte[] decode(CharSequence s) { 
  35.             int nChars = s.length(); 
  36.             if (nChars % 2 != 0) { 
  37.                 throw new IllegalArgumentException("16進(jìn)制數(shù)據(jù)錯(cuò)誤"); 
  38.             } 
  39.             byte[] result = new byte[nChars / 2]; 
  40.             for (int i = 0; i < nChars; i += 2) { 
  41.                 int msb = Character.digit(s.charAt(i), 16); 
  42.                 int lsb = Character.digit(s.charAt(i + 1), 16); 
  43.                 if (msb < 0 || lsb < 0) { 
  44.                     throw new IllegalArgumentException( 
  45.                         "Detected a Non-hex character at " + (i + 1) + " or " + (i + 2) + " position"); 
  46.                 } 
  47.                 result[i / 2] = (byte) ((msb << 4) | lsb); 
  48.             } 
  49.             return result; 
  50.         } 
  51.          
  52.         public static String encode(byte[] buf) { 
  53.             StringBuilder sb = new StringBuilder() ; 
  54.             for (int i = 0, leng = buf.length; i < leng; i++) { 
  55.                 sb.append(HEX[(buf[i] & 0xF0) >>> 4]).append(HEX[buf[i] & 0x0F]) ; 
  56.             } 
  57.             return sb.toString() ; 
  58.         } 
  59.          
  60.     } 
  61.      

該接口中定義了兩個(gè)方法分別是加密與解密的方法,還有Hex類 該類用來(lái)對(duì)數(shù)據(jù)處理16進(jìn)制的轉(zhuǎn)換。

定義一個(gè)抽象類實(shí)現(xiàn)上面的接口,具體的加解密實(shí)現(xiàn)細(xì)節(jié)在該抽象類中

AbstractSecretProcess.java

  1. public abstract class AbstractSecretProcess implements SecretProcess { 
  2.      
  3.     @Resource 
  4.     private SecretProperties props ; 
  5.      
  6.     @Override 
  7.     public String decrypt(String data) { 
  8.         try { 
  9.             Cipher cipher = Cipher.getInstance(getAlgorithm()) ; 
  10.             cipher.init(Cipher.DECRYPT_MODE, keySpec()) ; 
  11.             byte[] decryptBytes = cipher.doFinal(Hex.decode(data)) ; 
  12.             return new String(decryptBytes) ; 
  13.         } catch (Exception e) { 
  14.             throw new RuntimeException(e) ; 
  15.         } 
  16.     } 
  17.      
  18.     @Override 
  19.     public String encrypt(String data) { 
  20.         try { 
  21.             Cipher cipher = Cipher.getInstance(getAlgorithm()) ; 
  22.             cipher.init(Cipher.ENCRYPT_MODE, keySpec()) ; 
  23.             return Hex.encode(cipher.doFinal(data.getBytes(Charset.forName("UTF-8")))) ; 
  24.         } catch (Exception e) { 
  25.             throw new RuntimeException(e) ; 
  26.         } 
  27.     } 
  28.      
  29.     /** 
  30.      *  <p>根據(jù)密鑰生成不同的密鑰材料</p> 
  31.      *  <p>目前支持:AES, DES</p> 
  32.      *  <p>時(shí)間:2020年12月25日-下午1:02:54</p> 
  33.      * @author xg 
  34.      * @param secretKey 密鑰 
  35.      * @param algorithm 算法 
  36.      * @return Key 
  37.      */ 
  38.     public Key getKeySpec(String algorithm) { 
  39.         if (algorithm == null || algorithm.trim().length() == 0) { 
  40.             return null ; 
  41.         } 
  42.         String secretKey = props.getKey() ; 
  43.         switch (algorithm.toUpperCase()) { 
  44.             case "AES"
  45.                 return new SecretKeySpec(secretKey.getBytes(), "AES") ; 
  46.             case "DES"
  47.                 Key key = null ; 
  48.                 try { 
  49.                     DESKeySpec desKeySpec = new DESKeySpec(secretKey.getBytes()) ; 
  50.                     SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES") ; 
  51.                     key = secretKeyFactory.generateSecret(desKeySpec); 
  52.                 } catch (Exception e) { 
  53.                     throw new RuntimeException(e) ; 
  54.                 } 
  55.                 return key ; 
  56.             default
  57.                 return null ; 
  58.         } 
  59.     } 
  60.      
  61.     /** 
  62.      *  <p>生成密鑰材料</p> 
  63.      *  <p>時(shí)間:2020年12月25日-上午11:35:03</p> 
  64.      * @author xg 
  65.      * @return Key 密鑰材料 
  66.      */ 
  67.     public abstract Key keySpec() ; 
  68.      

該抽象類中提供了2中對(duì)稱加密的密鑰還原,分表是AES和DES算法。一個(gè)抽象方法,該抽象方法

keySpec該方法需要子類實(shí)現(xiàn)(具體使用的是哪種對(duì)稱加密算法)。

具體加密算法的實(shí)現(xiàn)類

AESAlgorithm.java

  1. public class AESAlgorithm extends AbstractSecretProcess { 
  2.  
  3.     @Override 
  4.     public String getAlgorithm() { 
  5.         return "AES/ECB/PKCS5Padding"
  6.     } 
  7.      
  8.     @Override 
  9.     public Key keySpec() { 
  10.         return this.getKeySpec("AES") ; 
  11.     } 
  12.  

SecretProperties.java 屬性配置類

  1. @Configuration 
  2. public class SecretConfig { 
  3.      
  4.     @Bean 
  5.     @ConditionalOnMissingBean(SecretProcess.class) 
  6.     public SecretProcess secretProcess() { 
  7.         return new AESAlgorithm() ; 
  8.     } 
  9.      
  10.     @Component 
  11.     @ConfigurationProperties(prefix = "secret"
  12.     public static class SecretProperties { 
  13.          
  14.         private Boolean enabled ; 
  15.         private String key ; 
  16.  
  17.         public Boolean getEnabled() { 
  18.             return enabled; 
  19.         } 
  20.  
  21.         public void setEnabled(Boolean enabled) { 
  22.             this.enabled = enabled; 
  23.         } 
  24.  
  25.         public String getKey() { 
  26.             return key
  27.         } 
  28.  
  29.         public void setKey(String key) { 
  30.             this.key = key
  31.         } 
  32.          
  33.     } 
  34.      

配置文件中如下配置:

  1. secret: 
  2.   key: aaaabbbbccccdddd #密鑰 
  3.   enabled: true #是否開(kāi)啟加解密功能 

在項(xiàng)目中可能不是所有的方法都要進(jìn)行數(shù)據(jù)的加密解密出來(lái),所以接下來(lái)定義一個(gè)注解,只有添加有該注解的Controller類或是具體接口方法才進(jìn)行數(shù)據(jù)的加密解密,如下:

SIProtection.java

  1. @Target({ElementType.METHOD, ElementType.TYPE}) 
  2. @Retention(RetentionPolicy.RUNTIME) 
  3. @Mapping 
  4. @Documented 
  5. public @interface SIProtection { 
  6.  

對(duì)請(qǐng)求內(nèi)容進(jìn)行解密出來(lái),通過(guò)RequestBodyAdvice

DecryptRequestBodyAdivce.java

  1. @ControllerAdvice 
  2. @ConditionalOnProperty(name = "secret.enabled", havingValue = "true"
  3. public class DecryptRequestBodyAdivce extends RequestBodyAdviceAdapter { 
  4.  
  5.     @Resource 
  6.     private SecretProcess secretProcess ; 
  7.      
  8.     @Override 
  9.     public boolean supports(MethodParameter methodParameter, Type targetType, 
  10.             Class<? extends HttpMessageConverter<?>> converterType) { 
  11.         return methodParameter.getMethod().isAnnotationPresent(SIProtection.class)  
  12.                 || methodParameter.getMethod().getDeclaringClass().isAnnotationPresent(SIProtection.class) ; 
  13.     } 
  14.  
  15.     @Override 
  16.     public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, 
  17.             Class<? extends HttpMessageConverter<?>> converterType) throws IOException { 
  18.         String body = secretProcess.decrypt(inToString(inputMessage.getBody())) ; 
  19.         return new HttpInputMessage() { 
  20.             @Override 
  21.             public HttpHeaders getHeaders() { 
  22.                 return inputMessage.getHeaders(); 
  23.             } 
  24.             @Override 
  25.             public InputStream getBody() throws IOException { 
  26.                 return new ByteArrayInputStream(body.getBytes()) ; 
  27.             } 
  28.         } ; 
  29.     } 
  30.      
  31.     private String inToString(InputStream is) { 
  32.         byte[] buf = new byte[10 * 1024] ; 
  33.         int leng = -1 ; 
  34.         StringBuilder sb = new StringBuilder() ; 
  35.         try { 
  36.             while ((leng = is.read(buf)) != -1) { 
  37.                 sb.append(new String(buf, 0, leng)) ; 
  38.             } 
  39.             return sb.toString() ; 
  40.         } catch (IOException e) { 
  41.             throw new RuntimeException(e) ; 
  42.         } 
  43.     } 
  44.  

注意這里的:@ConditionalOnProperty(name = "secret.enabled", havingValue = "true")注解,只有開(kāi)啟了加解密功能才會(huì)生效。注意這里的supports方法

對(duì)響應(yīng)內(nèi)容加密出來(lái)

EncryptResponseBodyAdivce.java

  1. @ControllerAdvice 
  2. @ConditionalOnProperty(name = "secret.enabled", havingValue = "true"
  3. public class EncryptResponseBodyAdivce implements ResponseBodyAdvice<Object>  { 
  4.  
  5.     @Resource 
  6.     private SecretProcess secretProcess ; 
  7.  
  8.     @Override 
  9.     public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) { 
  10.         return returnType.getMethod().isAnnotationPresent(SIProtection.class)  
  11.                 || returnType.getMethod().getDeclaringClass().isAnnotationPresent(SIProtection.class) ; 
  12.     } 
  13.  
  14.     @Override 
  15.     public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, 
  16.             Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, 
  17.             ServerHttpResponse response) { 
  18.         if (body == null) { 
  19.             return body ; 
  20.         } 
  21.         try { 
  22.             String jsonStr = new ObjectMapper().writeValueAsString(body) ; 
  23.             return secretProcess.encrypt(jsonStr) ; 
  24.         } catch (Exception e) { 
  25.             throw new RuntimeException(e) ; 
  26.         } 
  27.     } 

Controller應(yīng)用

  1. @PostMapping("/save"
  2.     @SIProtection 
  3.     public R save(@RequestBody Users users) { 
  4.         return R.success(usersService.save(users)) ; 
  5.     } // 這對(duì)具體方法進(jìn)行加解密 
  6.  
  7. @RestController 
  8. @RequestMapping("/users"
  9. @SIProtection  
  10. public class UsersController { // 對(duì)該Controller中的所有方法進(jìn)行加解密處理 

前端

引入第三方插件:crypto-js

工具方法加解密:

  1. /** 
  2.      * 加密方法 
  3.      * @param data 待加密數(shù)據(jù) 
  4.      * @returns {string|*} 
  5.      */ 
  6.     encrypt (data) { 
  7.       let key = CryptoJS.enc.Utf8.parse(Consts.Secret.key
  8.       if (typeof data === 'object') { 
  9.         data = JSON.stringify(data) 
  10.       } 
  11.       let plainText = CryptoJS.enc.Utf8.parse(data) 
  12.       let secretText = CryptoJS.AES.encrypt(plainText, key, {mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7}).ciphertext.toString() 
  13.       return secretText 
  14.     }, 
  15.     /** 
  16.      * 解密數(shù)據(jù) 
  17.      * @param data 待解密數(shù)據(jù) 
  18.      */ 
  19.     decrypt (data) { 
  20.       let key = CryptoJS.enc.Utf8.parse(Consts.Secret.key
  21.       let secretText = CryptoJS.enc.Hex.parse(data) 
  22.       let encryptedBase64Str = CryptoJS.enc.Base64.stringify(secretText) 
  23.       let result = CryptoJS.AES.decrypt(encryptedBase64Str, key, {mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7}).toString(CryptoJS.enc.Utf8) 
  24.       return JSON.parse(result) 
  25.     } 

配置:

  1. let Consts = { 
  2.   Secret: { 
  3.     key'aaaabbbbccccdddd', // 必須16位(前后端要一致,密鑰) 
  4.     urls: ['/users/save'
  5.   } 
  6. export default Consts 

這里的urls表示對(duì)那些請(qǐng)求進(jìn)行攔截出來(lái)(加解密),這里也可以配置 "*" 表示對(duì)所有的請(qǐng)求出來(lái)。

axios請(qǐng)求前和響應(yīng)后對(duì)數(shù)據(jù)進(jìn)行加解密出來(lái):

發(fā)送請(qǐng)求前:

  1. axios.interceptors.request.use((config) => { 
  2.       let uri = config.url 
  3.       if (uri.includes('?')) { 
  4.         uri = uri.substring(0, uri.indexOf('?')) 
  5.       } 
  6.       if (window.cfg.enableSecret === '1' && config.data && (Consts.Secret.urls.indexOf('*') > -1 || Consts.Secret.urls.indexOf(uri) > -1)) { 
  7.         let data = config.data 
  8.         let secretText = Utils.Secret.encrypt(data) 
  9.         config.data = secretText 
  10.       } 
  11.       return config 
  12.     }, (error) => { 
  13.       let errorMessage = '請(qǐng)求失敗' 
  14.       store.dispatch(types.G_SHOW_ALERT, {title: '請(qǐng)求失敗', content: errorMessage, showDetail: false, detailContent: String(error)}) 
  15.       return Promise.reject(error) 
  16.     }) 
  17. axios.interceptors.response.use((response) => { 
  18.       let uri = response.config.url 
  19.       if (uri.includes('?')) { 
  20.         uri = uri.substring(0, uri.indexOf('?')) 
  21.       } 
  22.       if (window.cfg.enableSecret === '1' && response.data && (Consts.Secret.urls.indexOf('*') > -1 || Consts.Secret.urls.indexOf(uri) > -1)) { 
  23.         let data = Utils.Secret.decrypt(response.data) 
  24.         if (data) { 
  25.           response.data = data 
  26.         } 
  27.       } 
  28.       return response 
  29.     }, (error) => { 
  30.       console.error(`test interceptors.response is in, ${error}`) 
  31.       return Promise.reject(error) 
  32.     }) 

這里的 window.cfg.enableSecret 配置是我自己項(xiàng)目中有個(gè)配置文件配置是否開(kāi)啟,這個(gè)大家可以根據(jù)自己的環(huán)境來(lái)實(shí)現(xiàn)。

測(cè)試:

Springboot 數(shù)據(jù)安全傳輸加密與解密

這里可以看到前端發(fā)起的請(qǐng)求內(nèi)容已經(jīng)被加密了

響應(yīng)內(nèi)容:

Springboot 數(shù)據(jù)安全傳輸加密與解密

完畢!!!

原文地址:https://www.toutiao.com/i6914092084014170628/

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 极品妖艳许清赵丽全文免费阅读 | 北条麻妃黑人 | www.色婷婷.com | 99久久免费国内精品 | 国产亚洲精品激情一区二区三区 | 国产亚洲精品视频中文字幕 | 日本大片网 | 99热这里只精品99re66 | 禁忌4中文 | 青青草久| 亚洲精品免费在线观看 | 国产视频二区 | 5566中文字幕亚洲精品 | 白丝出水 | free service性v极品 | 深夜激情网 | 免费成年人在线视频 | 女生被草 | 啾咪成人漫画免费 | 亚洲精品免费观看 | 日本春菜花在线中文字幕 | 99久久免费看精品国产一区 | 亚洲高清色图 | 亚洲人成伊人成综合网久久 | 久久精品黄AA片一区二区三区 | 成人在线观看视频免费 | girlfriend动漫在线播放 | 日韩香蕉视频 | 成年人视频在线免费看 | 国产精品污双胞胎在线观看 | 欧美最猛性xxxxx动态图 | 成人免费淫片95视频观看网站 | 精品综合久久久久久97超人 | 色老板美国在线观看 | 手机在线观看网站免费视频 | 色综合色狠狠天天久久婷婷基地 | 免费观看无人区完整版 | 国产精品麻豆99久久 | 男人天堂视频网 | 国产美女久久精品香蕉69 | 精品国产欧美一区二区五十路 |