VUE+SpringBoot实现传输加密
VUE+SpringBoot实现传输加密背景前段时间公司做项目,该项目涉及到的敏感数据比较多,经过的一波讨论之后,决定前后端进行接口加密处理,采用的是AES+BASE64算法加密~为实现AES,自然而然想到“crypto”。上网查询相关的技术或工具,一大堆最后自我选型前端采用cryptoJS、后端使用了hutool(糊涂)开源工具,接下来上手开干。前端1、引入cryptoJSnpm install
VUE+SpringBoot实现传输加密
背景
前段时间公司做项目,该项目涉及到的敏感数据比较多,经过的一波讨论之后,决定前后端进行接口加密处理,采用的是 AES
+ BASE64
算法加密~
为实现AES,自然而然想到“crypto”。上网查询相关的技术或工具,一大堆最后自我选型前端采用cryptoJS、后端使用了hutool(糊涂)开源工具,接下来上手开干。
前端
1、引入cryptoJS
npm install crypto-js --save-dev
2、编写加密/解密函数
const CRYPTOJSKEY= "afDeffjlj0343jjF";//前后端定义的密钥,AES使用16位
// 加密
function encrypt(plaintText) {
var plaintText = plaintText;
var options = {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
};
var key = CryptoJS.enc.Utf8.parse(CRYPTOJSKEY);
var encryptedData = CryptoJS.AES.encrypt(plaintText, key, options);
var encryptedBase64Str = encryptedData.toString().replace(/\//g, "_");
encryptedBase64Str = encryptedBase64Str.replace(/\+/g,"-");
return encryptedBase64Str;
}
//解密
function decrypt(encryptedBase64Str) {
var vals = encryptedBase64Str.replace(/\-/g, '+').replace(/_/g, '/');
var options = {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
};
var key = CryptoJS.enc.Utf8.parse(CRYPTOJSKEY);
var decryptedData = CryptoJS.AES.decrypt(vals, key, options);
var decryptedStr = CryptoJS.enc.Utf8.stringify(decryptedData);
return decryptedStr
}
3、前端数据加密
注:根据自身项目选择使用数据加密代码
我采用请求前拦截操作,encrypt(JSON.stringify(config.data))部分为使用代码 ,如下:
// request interceptor
instance.interceptors.request.use(
config => {
// Do something before request is sent
if (store.getters.token) {
config.headers["Authorization"] = `Bearer ${getToken()}`; // 让每个请求携带token-- ['X-Token']为自定义key 请根据实际情况自行修改
}
config.data = encrypt(JSON.stringify(config.data))
return config;
},
error => {
// Do something with request error
Message.error("对不起,出错了");
console.log(error); // for debug
Promise.reject(error);
}
);
4、axios请求
注:根据自身编写axios请求,但请求头中Content-Type需为:application/json;charset=UTF-8
export const createAPI = (url, method, data) => {
let config = {};
if (method === "get") {
config.params = data;
} else {
config.data = data;
}
config.headers = {
"Content-Type": "application/json;charset=UTF-8"
};
return instance({
url,
method,
...config
});
};
5、请求结果
后端
1、引入hutool
本人是Maven项目,即在pom.xml添加
<!--糊涂工具 https://github.com/looly/hutool/-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.4.7</version>
</dependency>
2、处理方案(即拦截)定位
分析:
1、数据加密/解密主要是针对请求/响应的body进行处理。
2、springboot前后端对接点为Controler。
3、如何实现在Controler接收前就实现拦截处理呢?
方案一、
提及到拦截大多数人会想到拦截器、过滤器,在此不做采用方案。
方案二、(采用方案)
1、提及到body,spring中有没有相关的类就能操作body呢?
答案:RequestBodyAdvice与ResponseBodyAdvice
我们来看看这2个类源码
RequestBodyAdvice:
package org.springframework.web.servlet.mvc.method.annotation;
import java.io.IOException;
import java.lang.reflect.Type;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.lang.Nullable;
public interface RequestBodyAdvice {
boolean supports(MethodParameter var1, Type var2, Class<? extends HttpMessageConverter<?>> var3);
HttpInputMessage beforeBodyRead(HttpInputMessage var1, MethodParameter var2, Type var3, Class<? extends HttpMessageConverter<?>> var4) throws IOException;
Object afterBodyRead(Object var1, HttpInputMessage var2, MethodParameter var3, Type var4, Class<? extends HttpMessageConverter<?>> var5);
@Nullable
Object handleEmptyBody(@Nullable Object var1, HttpInputMessage var2, MethodParameter var3, Type var4, Class<? extends HttpMessageConverter<?>> var5);
}
ResponseBodyAdvice:
package org.springframework.web.servlet.mvc.method.annotation;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.lang.Nullable;
public interface ResponseBodyAdvice<T> {
boolean supports(MethodParameter var1, Class<? extends HttpMessageConverter<?>> var2);
@Nullable
T beforeBodyWrite(@Nullable T var1, MethodParameter var2, MediaType var3, Class<? extends HttpMessageConverter<?>> var4, ServerHttpRequest var5, ServerHttpResponse var6);
}
看到beforeBodyRead与beforeBodyWrite这2个接口了吧!开不开心正式我们想要的东西。那我来实现他吧:
自定义请求实现类DecryptRequestBodyAdvice.java:
/**
* 请求数据接收处理类<br>
*
* 对加了@Decrypt的方法的数据进行解密操作<br>
*
* 只对 @RequestBody 参数有效
* @author xxm
*/
@ControllerAdvice
public class DecryptRequestBodyAdvice implements RequestBodyAdvice {
@Value("${crypto.charset}")
private String charset = "UTF-8";
@Value("${crypto.key}")
private String key;
@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 , key);
// }
// return inputMessage;
return new DecryptHttpInputMessage(inputMessage , charset , key);//请求信息解密,参考DecryptHttpInputMessage解密类
}
@Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
Class<? extends HttpMessageConverter<?>> converterType) {
return body;
}
}
自定义响应实现类EncryptResponseBodyAdvice.java:
/**
* 请求响应处理类<br>
*
* 对加了@Encrypt的方法的数据进行加密操作
*
* @author 熊诗言
*
*/
@ControllerAdvice
public class EncryptResponseBodyAdvice implements ResponseBodyAdvice<Object> {
@Value("${crypto.charset}")
private String charset = "UTF-8";
@Value("${crypto.key}")
private String key;
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return NeedCrypto.needEncrypt(returnType);
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
//TODO 实现具体的加密方法
System.out.println("________________");
return body;
}
}
注:必须加入@ControllerAdvice注解,没有它是没有注入到spring中的。
自定义请求信息解密类,DecryptHttpInputMessage.java:
/**
*
* @author xxm
*/
public class DecryptHttpInputMessage implements HttpInputMessage {
private HttpInputMessage inputMessage;
private String charset;
private String key;
public DecryptHttpInputMessage(HttpInputMessage inputMessage, String charset , String key) {
this.inputMessage = inputMessage;
this.charset = charset;
this.key = key;
}
@Override
public InputStream getBody() throws IOException {
//使用hutool开始解密
String content = IoUtil.read(inputMessage.getBody() , charset);
byte[] bytes = SecureUtil.aes(key.getBytes(charset)).decrypt(content);
return new ByteArrayInputStream(bytes);
}
@Override
public HttpHeaders getHeaders() {
return inputMessage.getHeaders();
}
}
更多推荐
所有评论(0)