在开始本文内容前,首先说一声:大家节日快乐!
本文来简单分析一下框架中请求加密的实现方式。该功能来源于框架 pr!377,后续进行了优化并手动合并到了框架 5.X 分支,并在版本 v5.1.0 正式发布。

PR 详情(传送门):

下面来看下具体的实现方式。
3.3.1^4.1.1package.json

v5.1.0hutool-crypto):5.8.22在上面的 PR 详情里面已经描述了具体的实现方式,下面分别对前端后端进行说明,前端部分由于是小白,所以只把相关的代码贴出来。
实现思路:

请求拦截器:
request.ts

随机生成AES密钥:
generateAesKey

对AES密钥进行Base64编码:
encryptBase64

编码后使用 RSA 公钥加密:
.env.development

RSA 公私钥应由服务端定义,前端持有公钥对数据加密,且两端公钥需要保持一致。
jsencrypt.ts

使用AES密钥对请求体进行加密:
crypto.ts

实现思路:
加密模块 ruoyi-common-encrypt:

application.yml
ApiDecryptProperties
CryptoFilter
DecryptRequestBodyWrapper
对于请求数据的解密主要在这个方法中实现。
完整代码:
package org.dromara.common.encrypt.filter;
import cn.hutool.core.io.IoUtil;
import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import org.dromara.common.core.constant.Constants;
import org.dromara.common.encrypt.utils.EncryptUtils;
import org.springframework.http.MediaType;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
/**
* 解密请求参数工具类
*
* @author wdhcr
*/
public class DecryptRequestBodyWrapper extends HttpServletRequestWrapper {
private final byte[] body;
public DecryptRequestBodyWrapper(HttpServletRequest request, String publicKey, String privateKey, String headerFlag) throws IOException {
super(request);
// 获取 AES 密码 采用 RSA 加密
String headerRsa = request.getHeader(headerFlag);
String decryptAes = EncryptUtils.decryptByRsa(headerRsa, privateKey);
// 解密 AES 密码
String aesPassword = EncryptUtils.decryptByBase64(decryptAes);
request.setCharacterEncoding(Constants.UTF8);
byte[] readBytes = IoUtil.readBytes(request.getInputStream(), false);
String requestBody = new String(readBytes, StandardCharsets.UTF_8);
// 解密 body 采用 AES 加密
String decryptBody = EncryptUtils.decryptByAes(requestBody, aesPassword);
body = decryptBody.getBytes(StandardCharsets.UTF_8);
}
@Override
public BufferedReader getReader() {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public int getContentLength() {
return body.length;
}
@Override
public long getContentLengthLong() {
return body.length;
}
@Override
public String getContentType() {
return MediaType.APPLICATION_JSON_VALUE;
}
@Override
public ServletInputStream getInputStream() {
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public int read() {
return bais.read();
}
@Override
public int available() {
return body.length;
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
};
}
}
EncryptUtilsEncryptUtils#decryptByRsa

EncryptUtils#decryptByBase64

EncryptUtils#decryptByAes

ApiDecryptAutoConfiguration

登录: [POST] /auth/login
对解密信息输出一下:




(跟上面步骤 2 的请求不是同一次请求,因此密钥不同,加密解密数据不同)


(完)