日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術(shù)文章
文章詳情頁

Spring Boot 接口參數(shù)加密解密的實現(xiàn)方法

瀏覽:73日期:2023-07-18 16:23:57

因為有小伙伴剛好問到這個問題,松哥就抽空擼一篇文章和大家聊聊這個話題。

加密解密本身并不是難事,問題是在何時去處理?定義一個過濾器,將請求和響應(yīng)分別攔截下來進行處理也是一個辦法,這種方式雖然粗暴,但是靈活,因為可以拿到一手的請求參數(shù)和響應(yīng)數(shù)據(jù)。不過 SpringMVC 中給我們提供了 ResponseBodyAdvice 和 RequestBodyAdvice,利用這兩個工具可以對請求和響應(yīng)進行預處理,非常方便。

所以今天這篇文章有兩個目的:

分享參數(shù)/響應(yīng)加解密的思路。 分享 ResponseBodyAdvice 和 RequestBodyAdvice 的用法。

好了,那么接下來就不廢話了,我們一起來看下。

1.開發(fā)加解密 starter

為了讓我們開發(fā)的這個工具更加通用,也為了復習一下自定義 Spring Boot Starter,這里我們就將這個工具做成一個 stater,以后在 Spring Boot 項目中直接引用就可以。

首先我們創(chuàng)建一個 Spring Boot 項目,引入 spring-boot-starter-web 依賴:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <scope>provided</scope> <version>2.4.3</version></dependency>

因為我們這個工具是為 Web 項目開發(fā)的,以后必然使用在 Web 環(huán)境中,所以這里添加依賴時 scope 設(shè)置為 provided。

依賴添加完成后,我們先來定義一個加密工具類備用,加密這塊有多種方案可以選擇,對稱加密、非對稱加密,其中對稱加密又可以使用 AES、DES、3DES 等不同算法,這里我們使用 Java 自帶的 Cipher 來實現(xiàn)對稱加密,使用 AES 算法:

public class AESUtils { private static final String AES_ALGORITHM = 'AES/ECB/PKCS5Padding'; // 獲取 cipher private static Cipher getCipher(byte[] key, int model) throws Exception { SecretKeySpec secretKeySpec = new SecretKeySpec(key, 'AES'); Cipher cipher = Cipher.getInstance(AES_ALGORITHM); cipher.init(model, secretKeySpec); return cipher; } // AES加密 public static String encrypt(byte[] data, byte[] key) throws Exception { Cipher cipher = getCipher(key, Cipher.ENCRYPT_MODE); return Base64.getEncoder().encodeToString(cipher.doFinal(data)); } // AES解密 public static byte[] decrypt(byte[] data, byte[] key) throws Exception { Cipher cipher = getCipher(key, Cipher.DECRYPT_MODE); return cipher.doFinal(Base64.getDecoder().decode(data)); }}

這個工具類比較簡單,不需要多解釋。需要說明的是,加密后的數(shù)據(jù)可能不具備可讀性,因此我們一般需要對加密后的數(shù)據(jù)再使用 Base64 算法進行編碼,獲取可讀字符串。換言之,上面的 AES 加密方法的返回值是一個 Base64 編碼之后的字符串,AES 解密方法的參數(shù)也是一個 Base64 編碼之后的字符串,先對該字符串進行解碼,然后再解密。

接下來我們封裝一個響應(yīng)工具類備用,這個大家如果經(jīng)常看松哥視頻已經(jīng)很了解了:

public class RespBean { private Integer status; private String msg; private Object obj; public static RespBean build() { return new RespBean(); } public static RespBean ok(String msg) { return new RespBean(200, msg, null); } public static RespBean ok(String msg, Object obj) { return new RespBean(200, msg, obj); } public static RespBean error(String msg) { return new RespBean(500, msg, null); } public static RespBean error(String msg, Object obj) { return new RespBean(500, msg, obj); } private RespBean() { } private RespBean(Integer status, String msg, Object obj) { this.status = status; this.msg = msg; this.obj = obj; } public Integer getStatus() { return status; } public RespBean setStatus(Integer status) { this.status = status; return this; } public String getMsg() { return msg; } public RespBean setMsg(String msg) { this.msg = msg; return this; } public Object getObj() { return obj; } public RespBean setObj(Object obj) { this.obj = obj; return this; }}

接下來我們定義兩個注解 @Decrypt 和 @Encrypt:

@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.METHOD,ElementType.PARAMETER})public @interface Decrypt {}@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface Encrypt {}

這兩個注解就是兩個標記,在以后使用的過程中,哪個接口方法添加了 @Encrypt 注解就對哪個接口的數(shù)據(jù)加密返回,哪個接口/參數(shù)添加了 @Decrypt 注解就對哪個接口/參數(shù)進行解密。這個定義也比較簡單,沒啥好說的,需要注意的是 @Decrypt 比 @Encrypt 多了一個使用場景就是 @Decrypt 可以用在參數(shù)上。

考慮到用戶可能會自己配置加密的 key,因此我們再來定義一個 EncryptProperties 類來讀取用戶配置的 key:

@ConfigurationProperties(prefix = 'spring.encrypt')public class EncryptProperties { private final static String DEFAULT_KEY = 'www.itboyhub.com'; private String key = DEFAULT_KEY; public String getKey() { return key; } public void setKey(String key) { this.key = key; }}

這里我設(shè)置了默認的 key 是 www.itboyhub.com,key 是 16 位字符串,松哥這個網(wǎng)站地址剛好滿足。以后如果用戶想自己配置 key,只需要在 application.properties 中配置 spring.encrypt.key=xxx 即可。

所有準備工作做完了,接下來就該正式加解密了。

因為松哥這篇文章一個很重要的目的是想和大家分享 ResponseBodyAdvice 和 RequestBodyAdvice 的用法,RequestBodyAdvice 在做解密的時候倒是沒啥問題,而 ResponseBodyAdvice 在做加密的時候則會有一些局限,不過影響不大,還是我前面說的,如果想非常靈活的掌控一切,那還是自定義過濾器吧。這里我就先用這兩個工具來實現(xiàn)了。

另外還有一點需要注意,ResponseBodyAdvice 在你使用了 @ResponseBody 注解的時候才會生效,RequestBodyAdvice 在你使用了 @RequestBody 注解的時候才會生效,換言之,前后端都是 JSON 交互的時候,這兩個才有用。不過一般來說接口加解密的場景也都是前后端分離的時候才可能有的事。

先來看接口加密:

@EnableConfigurationProperties(EncryptProperties.class)@ControllerAdvicepublic class EncryptResponse implements ResponseBodyAdvice<RespBean> { private ObjectMapper om = new ObjectMapper(); @Autowired EncryptProperties encryptProperties; @Override public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) { return returnType.hasMethodAnnotation(Encrypt.class); } @Override public RespBean beforeBodyWrite(RespBean body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { byte[] keyBytes = encryptProperties.getKey().getBytes(); try { if (body.getMsg()!=null) { body.setMsg(AESUtils.encrypt(body.getMsg().getBytes(),keyBytes)); } if (body.getObj() != null) { body.setObj(AESUtils.encrypt(om.writeValueAsBytes(body.getObj()), keyBytes)); } } catch (Exception e) { e.printStackTrace(); } return body; }}

我們自定義 EncryptResponse 類實現(xiàn) ResponseBodyAdvice 接口,泛型表示接口的返回類型,這里一共要實現(xiàn)兩個方法:

supports:這個方法用來判斷什么樣的接口需要加密,參數(shù) returnType 表示返回類型,我們這里的判斷邏輯就是方法是否含有 @Encrypt 注解,如果有,表示該接口需要加密處理,如果沒有,表示該接口不需要加密處理。 beforeBodyWrite:這個方法會在數(shù)據(jù)響應(yīng)之前執(zhí)行,也就是我們先對響應(yīng)數(shù)據(jù)進行二次處理,處理完成后,才會轉(zhuǎn)成 json 返回。我們這里的處理方式很簡單,RespBean 中的 status 是狀態(tài)碼就不用加密了,另外兩個字段重新加密后重新設(shè)置值即可。 另外需要注意,自定義的 ResponseBodyAdvice 需要用 @ControllerAdvice 注解來標記。

再來看接口解密:

@EnableConfigurationProperties(EncryptProperties.class)@ControllerAdvicepublic class DecryptRequest extends RequestBodyAdviceAdapter { @Autowired EncryptProperties encryptProperties; @Override public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) { return methodParameter.hasMethodAnnotation(Decrypt.class) || methodParameter.hasParameterAnnotation(Decrypt.class); } @Override public HttpInputMessage beforeBodyRead(final HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException { byte[] body = new byte[inputMessage.getBody().available()]; inputMessage.getBody().read(body); try { byte[] decrypt = AESUtils.decrypt(body, encryptProperties.getKey().getBytes()); final ByteArrayInputStream bais = new ByteArrayInputStream(decrypt); return new HttpInputMessage() { @Override public InputStream getBody() throws IOException { return bais; } @Override public HttpHeaders getHeaders() { return inputMessage.getHeaders(); } }; } catch (Exception e) { e.printStackTrace(); } return super.beforeBodyRead(inputMessage, parameter, targetType, converterType); }} 首先大家注意,DecryptRequest 類我們沒有直接實現(xiàn) RequestBodyAdvice 接口,而是繼承自 RequestBodyAdviceAdapter 類,該類是 RequestBodyAdvice 接口的子類,并且實現(xiàn)了接口中的一些方法,這樣當我們繼承自 RequestBodyAdviceAdapter 時,就只需要根據(jù)自己實際需求實現(xiàn)某幾個方法即可。 supports:該方法用來判斷哪些接口需要處理接口解密,我們這里的判斷邏輯是方法上或者參數(shù)上含有 @Decrypt 注解的接口,處理解密問題。 beforeBodyRead:這個方法會在參數(shù)轉(zhuǎn)換成具體的對象之前執(zhí)行,我們先從流中加載到數(shù)據(jù),然后對數(shù)據(jù)進行解密,解密完成后再重新構(gòu)造 HttpInputMessage 對象返回。

接下來,我們再來定義一個自動化配置類,如下:

@Configuration@ComponentScan('org.javaboy.encrypt.starter')public class EncryptAutoConfiguration {}

這個也沒啥好說的,比較簡單。

最后,resources 目錄下定義 META-INF,然后再定義 spring.factories 文件,內(nèi)容如下:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.javaboy.encrypt.starter.autoconfig.EncryptAutoConfiguration

這樣當項目啟動時,就會自動加載該配置類。

至此,我們的 starter 就開發(fā)完成啦。

2.打包發(fā)布

我們可以將項目安裝到本地倉庫,也可以發(fā)布到線上供他人使用。

2.1 安裝到本地倉庫

安裝到本地倉庫比較簡單,直接 mvn install,或者在 IDEA 中,點擊右邊的 Maven,然后雙擊 install,如下:

Spring Boot 接口參數(shù)加密解密的實現(xiàn)方法

2.2 發(fā)布到線上

發(fā)不到線上我們可以使用 JitPack 來做。

首先我們在 GitHub 上創(chuàng)建一個倉庫,將我們的代碼上傳上去,這個過程應(yīng)該不用我多說吧。

上傳成功后,點擊右邊的 Create a new release 按鈕,發(fā)布一個正式版,如下:

Spring Boot 接口參數(shù)加密解密的實現(xiàn)方法

Spring Boot 接口參數(shù)加密解密的實現(xiàn)方法

發(fā)布成功后,打開 jitpack,輸入倉庫的完整路徑,點擊 lookup 按鈕,查找到之后,再點擊 Get it 按鈕完成構(gòu)建,如下:

Spring Boot 接口參數(shù)加密解密的實現(xiàn)方法

構(gòu)建成功后,JitPack 上會給出項目引用方式:

Spring Boot 接口參數(shù)加密解密的實現(xiàn)方法

注意引用時將 tag 改成你具體的版本號。

至此,我們的工具就已經(jīng)成功發(fā)布了!小伙伴們可以通過如下方式引用這個 starter:

<dependencies> <dependency> <groupId>com.github.lenve</groupId> <artifactId>encrypt-spring-boot-starter</artifactId> <version>0.0.3</version> </dependency></dependencies><repositories> <repository> <id>jitpack.io</id> <url>https://jitpack.io</url> </repository></repositories>3.應(yīng)用

我們創(chuàng)建一個普通的 Spring Boot 項目,引入 web 依賴,再引入我們剛剛的 starter 依賴,如下:

<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.github.lenve</groupId> <artifactId>encrypt-spring-boot-starter</artifactId> <version>0.0.3</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency></dependencies><repositories> <repository> <id>jitpack.io</id> <url>https://jitpack.io</url> </repository></repositories>

然后再創(chuàng)建一個實體類備用:

public class User { private Long id; private String username; //省略 getter/setter}

創(chuàng)建兩個測試接口:

@RestControllerpublic class HelloController { @GetMapping('/user') @Encrypt public RespBean getUser() { User user = new User(); user.setId((long) 99); user.setUsername('javaboy'); return RespBean.ok('ok', user); } @PostMapping('/user') public RespBean addUser(@RequestBody @Decrypt User user) { System.out.println('user = ' + user); return RespBean.ok('ok', user); }}

第一個接口使用了 @Encrypt 注解,所以會對該接口的數(shù)據(jù)進行加密(如果不使用該注解就不加密),第二個接口使用了 @Decrypt 所以會對上傳的參數(shù)進行解密,注意 @Decrypt 注解既可以放在方法上也可以放在參數(shù)上。

接下來啟動項目進行測試。

首先測試 get 請求接口:

Spring Boot 接口參數(shù)加密解密的實現(xiàn)方法

可以看到,返回的數(shù)據(jù)已經(jīng)加密。

再來測試 post 請求:

Spring Boot 接口參數(shù)加密解密的實現(xiàn)方法

可以看到,參數(shù)中的加密數(shù)據(jù)已經(jīng)被還原了。

如果用戶想要修改加密密鑰,可以在 application.properties 中添加如下配置:

spring.encrypt.key=1234567890123456

加密數(shù)據(jù)到了前端,前端也有一些 js 工具來處理加密數(shù)據(jù),這個松哥后面有空再和大家說說 js 的加解密。

4.小結(jié)

好啦,今天這篇文章主要是想和大家聊聊 ResponseBodyAdvice 和 RequestBodyAdvice 的用法,一些加密思路,當然 ResponseBodyAdvice 和 RequestBodyAdvice 還有很多其他的使用場景,小伙伴們可以自行探索~本文使用了對稱加密中的 AES 算法,大家也可以嘗試改成非對稱加密。

本文案例獲取地址如下所示:

starter 源碼地址:

https://github.com/lenve/encrypt-spring-boot-starter

使用案例源碼地址:

https://github.com/lenve/javaboy-code-samples

到此這篇關(guān)于Spring Boot 接口參數(shù)加密解密的實現(xiàn)方法的文章就介紹到這了,更多相關(guān)Spring Boot 接口參數(shù)加密解密內(nèi)容請搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標簽: Spring
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
免费欧美一区| 精品国产日韩欧美精品国产欧美日韩一区二区三区 | 国产高清精品二区| 日本午夜精品视频在线观看| 日韩国产欧美在线视频| 国产图片一区| 麻豆精品视频在线| 婷婷综合六月| 久久精品免费一区二区三区 | 六月丁香综合| 亚洲精品自拍| 久久久国产精品网站| 欧美激情另类| av不卡免费看| 国产色噜噜噜91在线精品| 国产一区2区| 婷婷亚洲综合| 91成人小视频| 在线看片国产福利你懂的| 999国产精品永久免费视频app| 国产精品毛片在线看| 欧美日一区二区三区在线观看国产免| 九九久久国产| 国产亚洲一级| 国产精品伦一区二区| 日本激情一区| 免播放器亚洲| 国产精品高潮呻吟久久久久| 日韩欧美一区二区三区免费观看| 欧美日韩四区| 国产精品qvod| 久久精品高清| 只有精品亚洲| 国产成人黄色| 狠狠爱www人成狠狠爱综合网| 日韩精品一区二区三区中文 | 精精国产xxxx视频在线野外| 蜜臀久久久久久久| 精品一区二区三区中文字幕 | 国产一区一一区高清不卡| 亚洲精品**中文毛片| 亚洲久久视频| 日韩欧美少妇| 国产日韩免费| 亚洲欧美日韩精品一区二区| 你懂的国产精品| 六月婷婷一区| 电影亚洲精品噜噜在线观看| 午夜精品影视国产一区在线麻豆| 欧美男人天堂| 欧美另类中文字幕| 欧洲激情综合| 欧美精品91| 一区二区国产在线观看| 一区二区三区四区日本视频| 中文字幕视频精品一区二区三区| 国产伦久视频在线观看| 日本成人在线视频网站| 99精品电影| 免费一级欧美在线观看视频| 日韩精品一级中文字幕精品视频免费观看 | 日韩激情网站| 午夜久久影院| 蜜桃成人精品| 免费日韩成人| 日韩中文字幕在线一区| 日韩精品网站| 国产精品1区| 涩涩涩久久久成人精品| 亚洲国产专区校园欧美| 美女高潮久久久| 欧美性www| 日本亚洲不卡| 亚洲日韩视频| 中文字幕一区二区三区在线视频| 国产一区观看| 亚洲www啪成人一区二区| 麻豆精品一区二区综合av| 久久激情综合网| 日韩av影院| 日韩av一区二区在线影视| 日韩在线一区二区| 亚洲欧美日韩国产一区二区| 欧美~级网站不卡| 久久黄色影院| 激情欧美丁香| 在线观看免费一区二区| 极品日韩av| 午夜日韩在线| 水蜜桃久久夜色精品一区的特点 | www.九色在线| 亚洲黄色网址| 久久久精品网| 视频一区中文| 久久视频一区| 午夜久久tv| 噜噜噜久久亚洲精品国产品小说| 亚洲一区日韩| 亚洲免费观看高清完整版在线观| 亚洲乱码久久| 欧美日韩亚洲一区三区| 国产精品黄色| 精品久久91| 欧美韩日一区| 日本韩国欧美超级黄在线观看| 欧美aa一级| 欧美日韩四区| 亚洲理论在线| 国产探花在线精品一区二区| 国产欧美在线观看免费| 国产精品v亚洲精品v日韩精品| 欧美a一区二区| 伊人久久视频| 亚洲欧洲一区二区天堂久久| 久久香蕉精品| 欧美专区一区| 国产一区二区久久久久| 92国产精品| 欧美亚洲精品在线| 中日韩男男gay无套| 亚洲最大av| 国产精品99久久免费| 国产精品yjizz视频网| 久久精品二区三区| 国产亚洲在线观看| 国产欧美日韩影院| 水蜜桃精品av一区二区| 国产99亚洲| 亚洲综合婷婷| 精品国产日韩欧美精品国产欧美日韩一区二区三区 | 国产精品亚洲欧美| 国产999精品在线观看| 午夜欧美精品久久久久久久| 日韩高清一区| 丰满少妇一区| 一本色道精品久久一区二区三区| 日韩av在线播放中文字幕| 岛国av免费在线观看| 夜久久久久久| 国产精品亚洲欧美一级在线| 久久久久免费av| 日本成人在线不卡视频| 91欧美在线| 午夜在线精品偷拍| 久久一区亚洲| 三级在线观看一区二区| 免费看久久久| 国产精品丝袜xxxxxxx| 捆绑调教美女网站视频一区| 在线亚洲欧美| 国产中文字幕一区二区三区| 欧美中文日韩| av最新在线| 亚洲人亚洲人色久| 日本欧美不卡| 久久99久久久精品欧美| 亚洲深夜福利| 国产66精品| 日韩欧美中文字幕一区二区三区| 最新中文字幕在线播放| 亚洲日本国产| 亚洲成人一区在线观看| 国产伦精品一区二区三区视频 | 天堂√中文最新版在线| 青草国产精品| 在线精品小视频| 成人在线黄色| 久久国产三级| 好吊视频一区二区三区四区| 久久97久久97精品免视看秋霞| 蜜桃久久av| 99精品国产一区二区三区| 91亚洲精品在看在线观看高清| 激情久久五月| 精品黄色一级片| 日韩av不卡一区二区| 国产亚洲亚洲| 在线日韩一区| 色综合狠狠操| 久久久国产精品网站| 亚久久调教视频| 男女精品网站| 欧美另类综合| 亚洲高清久久| 日本精品影院| 天堂а√在线最新版中文在线| 国产探花一区| 日精品一区二区三区| 性欧美精品高清| 激情综合激情| 激情久久婷婷| 亚洲a在线视频| 日韩av福利| 伊人久久在线| 捆绑调教日本一区二区三区| 久久97视频| 成人国产综合| 久久99国产精品视频| 精品一区二区三区在线观看视频| 国产精品久久久网站|