diff --git a/kernel-d-scanner/scanner-api/src/main/java/cn/stylefeng/roses/kernel/scanner/api/annotation/PostResource.java b/kernel-d-scanner/scanner-api/src/main/java/cn/stylefeng/roses/kernel/scanner/api/annotation/PostResource.java
index 3a87f2e49..704eae66c 100644
--- a/kernel-d-scanner/scanner-api/src/main/java/cn/stylefeng/roses/kernel/scanner/api/annotation/PostResource.java
+++ b/kernel-d-scanner/scanner-api/src/main/java/cn/stylefeng/roses/kernel/scanner/api/annotation/PostResource.java
@@ -77,6 +77,11 @@ public @interface PostResource {
*/
boolean requiredPermission() default true;
+ /**
+ * 是否需要请求解密,响应加密 (true-需要,false-不需要)
+ */
+ boolean requiredEncryption() default false;
+
/**
* 是否是视图类型:true-是,false-否
* 如果是视图类型,url需要以 '/view' 开头,
diff --git a/kernel-d-security/pom.xml b/kernel-d-security/pom.xml
index ed5e65408..41dab0480 100644
--- a/kernel-d-security/pom.xml
+++ b/kernel-d-security/pom.xml
@@ -21,6 +21,7 @@
security-sdk-captcha
security-sdk-count
security-sdk-xss
+ security-sdk-request-encrypt-and-decode
security-spring-boot-starter
diff --git a/kernel-d-security/security-sdk-request-encrypt-and-decode/README.md b/kernel-d-security/security-sdk-request-encrypt-and-decode/README.md
new file mode 100644
index 000000000..9c00f8fab
--- /dev/null
+++ b/kernel-d-security/security-sdk-request-encrypt-and-decode/README.md
@@ -0,0 +1,35 @@
+请求解密,响应加密模块
+
+大致流程 生成随机key并使用AES加密 模式为CFB 填充为Pkcs7 加密请求的内容,并使用RSA公钥加密生成的key,用于后端进行解密,后端再根据这个key加密响应结果
+
+前端实例代码
+
+```javascript
+ layui.use(['HttpEncryptionRequest'], function () {
+ var result = new HttpEncryptionRequest(Feng.ctxPath + '/encode', function (res) {
+ console.log(res)
+ })
+ result.set({name:'测试'});
+ result.start();
+ })
+```
+
+后端示例代码
+
+在 PostResource 注解中 requiredEncryption 参数设置为true 开启参数解密,响应加密 接收参数实体加上 @RequestBody 注解
+
+```java
+/**
+ * 示例加密方法
+ *
+ * requiredEncryption = true
+ *
+ *
+ * @author luojie
+ * @date 2021/3/27 22:31
+ */
+ @PostResource(name = "示例加密方法", path = "/encode", requiredPermission = false, requiredLogin = false, requiredEncryption = true)
+ public ResponseData encode(@RequestBody Dict dict) {
+ return new SuccessResponseData(dict);
+ }
+```
\ No newline at end of file
diff --git a/kernel-d-security/security-sdk-request-encrypt-and-decode/pom.xml b/kernel-d-security/security-sdk-request-encrypt-and-decode/pom.xml
new file mode 100644
index 000000000..99e67610e
--- /dev/null
+++ b/kernel-d-security/security-sdk-request-encrypt-and-decode/pom.xml
@@ -0,0 +1,49 @@
+
+
+ 4.0.0
+
+
+ cn.stylefeng.roses
+ kernel-d-security
+ 7.0.2
+ ../pom.xml
+
+
+ security-sdk-request-encrypt-and-decode
+
+ jar
+
+
+
+
+
+ org.bouncycastle
+ bcprov-jdk15to18
+ 1.68
+
+
+
+
+ cn.stylefeng.roses
+ security-api
+ 7.0.2
+
+
+
+
+ cn.stylefeng.roses
+ scanner-api
+ 7.0.2
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
+
diff --git a/kernel-d-security/security-sdk-request-encrypt-and-decode/src/main/java/cn/stylefeng/roses/kernel/security/request/encrypt/advice/EncryptionRequestBodyAdvice.java b/kernel-d-security/security-sdk-request-encrypt-and-decode/src/main/java/cn/stylefeng/roses/kernel/security/request/encrypt/advice/EncryptionRequestBodyAdvice.java
new file mode 100644
index 000000000..8dfef772c
--- /dev/null
+++ b/kernel-d-security/security-sdk-request-encrypt-and-decode/src/main/java/cn/stylefeng/roses/kernel/security/request/encrypt/advice/EncryptionRequestBodyAdvice.java
@@ -0,0 +1,209 @@
+package cn.stylefeng.roses.kernel.security.request.encrypt.advice;
+
+import cn.hutool.core.codec.Base64;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.util.CharsetUtil;
+import cn.hutool.core.util.HexUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.crypto.Mode;
+import cn.hutool.crypto.Padding;
+import cn.hutool.crypto.SecureUtil;
+import cn.hutool.crypto.asymmetric.KeyType;
+import cn.hutool.crypto.asymmetric.RSA;
+import cn.hutool.crypto.symmetric.AES;
+import cn.hutool.crypto.symmetric.SM4;
+import cn.stylefeng.roses.kernel.scanner.api.annotation.PostResource;
+import cn.stylefeng.roses.kernel.security.request.encrypt.constants.EncryptionConstants;
+import cn.stylefeng.roses.kernel.security.request.encrypt.exception.EncryptionException;
+import cn.stylefeng.roses.kernel.security.request.encrypt.exception.enums.EncryptionExceptionEnum;
+import cn.stylefeng.roses.kernel.security.request.encrypt.holder.EncryptionHolder;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.springframework.core.MethodParameter;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpInputMessage;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.security.Security;
+import java.util.Date;
+
+/**
+ * 请求参数解密
+ *
+ * @author luojie
+ * @date 2021/3/23 12:53
+ */
+@Slf4j
+@ControllerAdvice
+public class EncryptionRequestBodyAdvice implements RequestBodyAdvice {
+
+ static {
+ if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
+ // 添加PKCS7Padding支持
+ Security.addProvider(new com.sun.crypto.provider.SunJCE());
+ Security.addProvider(new BouncyCastleProvider());
+ }
+ }
+
+ /**
+ * 设置条件,这个条件为true才会执行下面的beforeBodyRead方法
+ *
+ * @param methodParameter
+ * @param targetType
+ * @param converterType
+ * @return
+ */
+ @Override
+ public boolean supports(MethodParameter methodParameter, Type targetType, Class extends HttpMessageConverter>> converterType) {
+ // 判断当前请求的接口中是否有 PostResource 注解
+ Annotation[] annotations = methodParameter.getAnnotatedElement().getAnnotations();
+ for (Annotation annotation : annotations) {
+ Class extends Annotation> annotationType = annotation.annotationType();
+ return PostResource.class.equals(annotationType);
+ }
+ return false;
+ }
+
+ @Override
+ public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class extends HttpMessageConverter>> converterType) throws IOException {
+ Method method = parameter.getMethod();
+ if (method != null) {
+ PostResource annotation = method.getAnnotation(PostResource.class);
+
+ if (annotation != null) {
+ // 是否需要加密
+ if (annotation.requiredEncryption()) {
+ return new HttpInputMessage() {
+ @Override
+ public HttpHeaders getHeaders() {
+ return inputMessage.getHeaders();
+ }
+
+ @Override
+ public InputStream getBody() throws IOException {
+
+ // 获取请求的内容
+ InputStream body = inputMessage.getBody();
+ String bodyStr = IoUtil.readUtf8(body);
+
+ //JSON 解析请求中的内容
+ JSONObject jsonObject = null;
+ try {
+ jsonObject = JSON.parseObject(bodyStr);
+ } catch (Exception e) {
+ e.printStackTrace();
+ log.error(e.getMessage());
+ log.error(StrUtil.format("请求的内容:{}", bodyStr));
+ // 请求json解析异常
+ throw new EncryptionException(EncryptionExceptionEnum.REQUEST_JSON_PARSE_ERROR);
+ }
+
+ // 使用私钥解密出返回加密数据的key和请求的内容
+ RSA rsa = new RSA(EncryptionConstants.PRIVATE_KEY, EncryptionConstants.PUBLIC_KEY);
+
+ // 先使用SM4解密出请求的json
+ String objectString = jsonObject.getString("data");
+ if (StrUtil.isBlank(objectString)) {
+ // 请求json解析异常
+ throw new EncryptionException(EncryptionExceptionEnum.REQUEST_JSON_PARSE_ERROR);
+ }
+
+ String sm4Key = SecureUtil.md5(DateUtil.format(new Date(), "yyyyMMdd"));
+ SM4 sm4 = new SM4(Mode.ECB, Padding.PKCS5Padding, HexUtil.decodeHex(sm4Key));
+ try {
+ String decryptStr = sm4.decryptStr(objectString);
+ jsonObject = JSON.parseObject(decryptStr);
+ } catch (Exception e) {
+ e.printStackTrace();
+ log.error(e.getMessage());
+ // 解密失败
+ throw new EncryptionException(EncryptionExceptionEnum.RSA_DECRYPT_ERROR);
+
+ }
+
+ // 请求中RSA公钥加密后的key 用于将返回的内容AES加密
+ String key = jsonObject.getString("key");
+
+ // 获取请求中 AES 加密后的数据
+ String data = jsonObject.getString("data");
+
+ if (StrUtil.isBlank(key) || StrUtil.isBlank(data)) {
+ // 请求的json格式错误,未包含加密的data字段数据以及加密的key字段
+ throw new EncryptionException(EncryptionExceptionEnum.REQUEST_JSON_ERROR);
+ }
+
+ String aesKey = null;
+ try {
+ // 使用 RSA 私钥解密请求中公钥加密后的key
+ aesKey = rsa.decryptStr(key, KeyType.PrivateKey, CharsetUtil.CHARSET_UTF_8);
+ log.info("本次请求数据AES加密的KEY为:" + aesKey);
+ } catch (Exception e) {
+ e.printStackTrace();
+ log.error(e.getMessage());
+ // 解密失败
+ throw new EncryptionException(EncryptionExceptionEnum.RSA_DECRYPT_ERROR);
+ }
+
+ byte[] iv = HexUtil.decodeHex(SecureUtil.md5(StrUtil.format("{}{}", aesKey, DateUtil.format(new Date(), "yyyyMMdd"))));
+ byte[] aesKeyByte = Base64.decode(aesKey);
+
+ AES aes = new AES("CFB", "PKCS7Padding", aesKeyByte, iv);
+ String reqData = null;
+ try {
+ // 使用aes解密请求的内容
+ reqData = aes.decryptStr(data);
+ log.info(StrUtil.format("本次请求的内容:{}", reqData));
+ } catch (Exception e) {
+ e.printStackTrace();
+ log.error(e.getMessage());
+ // 解密失败
+ throw new EncryptionException(EncryptionExceptionEnum.RSA_DECRYPT_ERROR);
+ }
+
+ log.info(StrUtil.format("返回数据加密的key:{}", aesKey));
+
+ // 将 AES KEY 放到 ThreadLocal 中
+ EncryptionHolder.setAesKey(aesKey);
+
+ return new ByteArrayInputStream(reqData.getBytes(CharsetUtil.CHARSET_UTF_8));
+ }
+ };
+ }
+ }
+ }
+
+ return inputMessage;
+
+ }
+
+ @Override
+ public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class extends HttpMessageConverter>> converterType) {
+ return body;
+ }
+
+ /**
+ * 传入的json是空值的时候,进入这个方法
+ *
+ * @param body
+ * @param inputMessage
+ * @param parameter
+ * @param targetType
+ * @param converterType
+ * @return
+ */
+ @Override
+ public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class extends HttpMessageConverter>> converterType) {
+ return body;
+ }
+}
diff --git a/kernel-d-security/security-sdk-request-encrypt-and-decode/src/main/java/cn/stylefeng/roses/kernel/security/request/encrypt/advice/EncryptionResponseBodyAdvice.java b/kernel-d-security/security-sdk-request-encrypt-and-decode/src/main/java/cn/stylefeng/roses/kernel/security/request/encrypt/advice/EncryptionResponseBodyAdvice.java
new file mode 100644
index 000000000..22e819e02
--- /dev/null
+++ b/kernel-d-security/security-sdk-request-encrypt-and-decode/src/main/java/cn/stylefeng/roses/kernel/security/request/encrypt/advice/EncryptionResponseBodyAdvice.java
@@ -0,0 +1,96 @@
+package cn.stylefeng.roses.kernel.security.request.encrypt.advice;
+
+import cn.hutool.core.codec.Base64;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.CharsetUtil;
+import cn.hutool.core.util.HexUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.crypto.SecureUtil;
+import cn.hutool.crypto.symmetric.AES;
+import cn.stylefeng.roses.kernel.rule.pojo.response.ResponseData;
+import cn.stylefeng.roses.kernel.scanner.api.annotation.PostResource;
+import cn.stylefeng.roses.kernel.security.request.encrypt.holder.EncryptionHolder;
+import com.alibaba.fastjson.JSON;
+import lombok.extern.slf4j.Slf4j;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.springframework.core.MethodParameter;
+import org.springframework.http.MediaType;
+import org.springframework.http.server.ServerHttpRequest;
+import org.springframework.http.server.ServerHttpResponse;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
+
+import java.security.Security;
+import java.util.Date;
+
+/**
+ * 响应结果加密
+ *
+ * @author luojie
+ * @date 2021/3/23 12:54
+ */
+@Slf4j
+@ControllerAdvice
+public class EncryptionResponseBodyAdvice implements ResponseBodyAdvice {
+
+ static {
+ if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
+ // 添加PKCS7Padding支持
+ Security.addProvider(new com.sun.crypto.provider.SunJCE());
+ Security.addProvider(new BouncyCastleProvider());
+ }
+ }
+
+ @Override
+ public boolean supports(MethodParameter returnType, Class converterType) {
+ return true;
+ }
+
+ @Override
+ public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
+ if (null != body) {
+
+ PostResource annotation = returnType.getMethod().getAnnotation(PostResource.class);
+
+ if (annotation != null) {
+ if (annotation.requiredEncryption()) {
+ // 判断响应实体是否是 ResponseData
+ if (body instanceof ResponseData) {
+ // 转换类型
+ ResponseData responseData = (ResponseData)body;
+
+ Object data = responseData.getData();
+
+ // 将返回的数据格式化成json字符串
+ String respJsonStr = JSON.toJSONString(data);
+
+ // 从 ThreadLocal 中获取 aes key
+ String aesKey = EncryptionHolder.getAesKey();
+ // 偏移
+ byte[] iv = HexUtil.decodeHex(SecureUtil.md5(StrUtil.format("{}{}", aesKey, DateUtil.format(new Date(), "yyyyMMdd"))));
+
+ if (StrUtil.isNotBlank(aesKey)) {
+
+ byte[] keyByte = Base64.decode(aesKey.getBytes(CharsetUtil.CHARSET_UTF_8));
+
+ // AES
+ AES aes = new AES("CFB", "PKCS7Padding", keyByte, iv);
+ String encryptBase64 = aes.encryptBase64(respJsonStr);
+
+ responseData.setData(encryptBase64);
+
+ }
+
+ // 清除当前线程中的aes key
+ EncryptionHolder.clearAesKey();
+
+ return responseData;
+
+ }
+ }
+ }
+
+ }
+ return body;
+ }
+}
diff --git a/kernel-d-security/security-sdk-request-encrypt-and-decode/src/main/java/cn/stylefeng/roses/kernel/security/request/encrypt/constants/EncryptionConstants.java b/kernel-d-security/security-sdk-request-encrypt-and-decode/src/main/java/cn/stylefeng/roses/kernel/security/request/encrypt/constants/EncryptionConstants.java
new file mode 100644
index 000000000..b6cb218a5
--- /dev/null
+++ b/kernel-d-security/security-sdk-request-encrypt-and-decode/src/main/java/cn/stylefeng/roses/kernel/security/request/encrypt/constants/EncryptionConstants.java
@@ -0,0 +1,32 @@
+package cn.stylefeng.roses.kernel.security.request.encrypt.constants;
+
+/**
+ * 请求解密,响应加密 常量
+ *
+ * @author luojie
+ * @date 2021/3/23 12:54
+ */
+public interface EncryptionConstants {
+
+ /**
+ * 公钥
+ */
+ String PUBLIC_KEY = "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwiRWfPs7Qds9K+gbabarxKOn71vZY9S7C5cmiTTmDoxvL8gixtlldbqaBCG0fhP48qxImw4jmAnXbSb51hDohTRXmGIuBEQuhIWwh28rorSiGuOye6PTbYNuup5CWwxMkD/ARHrs5Cvg9+vJTHXdg3TrRbwiW6GniDvVGPcl0d9TshX5Dgo6m9VZkLJfHJkVKmjAOOvede8uPgaM1ymt6JexjTcn6uiIrWlDkKTzvAq+Hb9cj9tz/Q5FKo17TF7oa4XC8lfximCzAvMwsl/kmqfh0cSNqeoW9s8LcjY0o7YexYJB3+jjp88QbzqXnUNYMVGz0M2cYLmAaM2LVwWvVrfs1HCB1o+WqGqjaBql/4apVyhqf77Py6M+2WUr1yKgDfRXjZ1h9w9e3jh3oQdjSk36fboJmHXBnKwwoecxW5csVJmj/M7CPP7Xw8BPGV4/rMmRKjBRTv5XdcRnnMm8nd8EdK/2AaXZqu0O2iRjQlFFgLNUzP+eudvLCA0+Dxczkpgvcr7S4oQtD+TCFm1gWaC+Kho5liMQ7OV0L7tL8O+tzzbKmoVj/fg8uIG5ljqsU6rE5WFUCl1w0v8Gzx1Yz3IXaRKmXTgmxZPdaN3nVA+YBT+N3EKQETVlN6w+65/HK/8ZsB36exrlkkxUo+y0umk0DzFFY/9i1x2kU7wXPzECAwEAAQ==";
+
+ /**
+ * 私钥
+ */
+ String PRIVATE_KEY =
+ "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";
+
+ /**
+ * 模块名
+ */
+ String ENCRYPTION_MODULE_NAME = "kernel-d-encryption";
+
+ /**
+ * 异常枚举的步进值
+ */
+ String ENCRYPTION_EXCEPTION_STEP_CODE = "29";
+
+}
diff --git a/kernel-d-security/security-sdk-request-encrypt-and-decode/src/main/java/cn/stylefeng/roses/kernel/security/request/encrypt/exception/EncryptionException.java b/kernel-d-security/security-sdk-request-encrypt-and-decode/src/main/java/cn/stylefeng/roses/kernel/security/request/encrypt/exception/EncryptionException.java
new file mode 100644
index 000000000..984b8c14d
--- /dev/null
+++ b/kernel-d-security/security-sdk-request-encrypt-and-decode/src/main/java/cn/stylefeng/roses/kernel/security/request/encrypt/exception/EncryptionException.java
@@ -0,0 +1,24 @@
+package cn.stylefeng.roses.kernel.security.request.encrypt.exception;
+
+import cn.hutool.core.util.StrUtil;
+import cn.stylefeng.roses.kernel.rule.exception.AbstractExceptionEnum;
+import cn.stylefeng.roses.kernel.rule.exception.base.ServiceException;
+import cn.stylefeng.roses.kernel.security.request.encrypt.constants.EncryptionConstants;
+
+/**
+ * 请求解密,响应加密 异常
+ *
+ * @author luojie
+ * @date 2021/3/23 12:54
+ */
+public class EncryptionException extends ServiceException {
+
+ public EncryptionException(AbstractExceptionEnum exception, Object... params) {
+ super(EncryptionConstants.ENCRYPTION_MODULE_NAME, exception.getErrorCode(), StrUtil.format(exception.getUserTip(), params));
+ }
+
+ public EncryptionException(AbstractExceptionEnum exception) {
+ super(EncryptionConstants.ENCRYPTION_MODULE_NAME, exception);
+ }
+
+}
diff --git a/kernel-d-security/security-sdk-request-encrypt-and-decode/src/main/java/cn/stylefeng/roses/kernel/security/request/encrypt/exception/enums/EncryptionExceptionEnum.java b/kernel-d-security/security-sdk-request-encrypt-and-decode/src/main/java/cn/stylefeng/roses/kernel/security/request/encrypt/exception/enums/EncryptionExceptionEnum.java
new file mode 100644
index 000000000..6ef3a104d
--- /dev/null
+++ b/kernel-d-security/security-sdk-request-encrypt-and-decode/src/main/java/cn/stylefeng/roses/kernel/security/request/encrypt/exception/enums/EncryptionExceptionEnum.java
@@ -0,0 +1,48 @@
+package cn.stylefeng.roses.kernel.security.request.encrypt.exception.enums;
+
+import cn.stylefeng.roses.kernel.rule.constants.RuleConstants;
+import cn.stylefeng.roses.kernel.rule.exception.AbstractExceptionEnum;
+import cn.stylefeng.roses.kernel.security.request.encrypt.constants.EncryptionConstants;
+import lombok.Getter;
+
+/**
+ * 请求解密,响应加密 异常枚举
+ *
+ * @author luojie
+ * @date 2021/3/23 12:54
+ */
+@Getter
+public enum EncryptionExceptionEnum implements AbstractExceptionEnum {
+
+ /**
+ * 请求的json解析异常
+ */
+ REQUEST_JSON_PARSE_ERROR(RuleConstants.BUSINESS_ERROR_TYPE_CODE + EncryptionConstants.ENCRYPTION_EXCEPTION_STEP_CODE + "01", "请求的json解析异常"),
+
+ /**
+ * 请求的json格式错误,未包含加密的data字段数据以及加密的key字段
+ */
+ REQUEST_JSON_ERROR(RuleConstants.BUSINESS_ERROR_TYPE_CODE + EncryptionConstants.ENCRYPTION_EXCEPTION_STEP_CODE + "02", "请求的json格式错误,未包含加密的data字段数据以及加密的key字段"),
+
+ /**
+ * 解密失败
+ */
+ RSA_DECRYPT_ERROR(RuleConstants.BUSINESS_ERROR_TYPE_CODE + EncryptionConstants.ENCRYPTION_EXCEPTION_STEP_CODE + "03", "解密失败"),
+
+ ;
+
+ /**
+ * 错误编码
+ */
+ private final String errorCode;
+
+ /**
+ * 提示用户信息
+ */
+ private final String userTip;
+
+ EncryptionExceptionEnum(String errorCode, String userTip) {
+ this.errorCode = errorCode;
+ this.userTip = userTip;
+ }
+}
diff --git a/kernel-d-security/security-sdk-request-encrypt-and-decode/src/main/java/cn/stylefeng/roses/kernel/security/request/encrypt/holder/EncryptionHolder.java b/kernel-d-security/security-sdk-request-encrypt-and-decode/src/main/java/cn/stylefeng/roses/kernel/security/request/encrypt/holder/EncryptionHolder.java
new file mode 100644
index 000000000..c10b73365
--- /dev/null
+++ b/kernel-d-security/security-sdk-request-encrypt-and-decode/src/main/java/cn/stylefeng/roses/kernel/security/request/encrypt/holder/EncryptionHolder.java
@@ -0,0 +1,43 @@
+package cn.stylefeng.roses.kernel.security.request.encrypt.holder;
+
+/**
+ * 用于存储响应加密秘钥
+ *
+ * @author luojie
+ * @date 2021/3/23 12:54
+ */
+public class EncryptionHolder {
+
+ private static final ThreadLocal CONTEXT_HOLDER = new ThreadLocal<>();
+
+ /**
+ * 设置
+ *
+ * @param aesKey aesKey
+ * @date 2020/8/24
+ */
+ public static void setAesKey(String aesKey) {
+ CONTEXT_HOLDER.set(aesKey);
+ }
+
+ /**
+ * 获取
+ *
+ * @author fengshuonan
+ * @date 2020/8/24
+ */
+ public static String getAesKey() {
+ return CONTEXT_HOLDER.get();
+ }
+
+ /**
+ * 清除
+ *
+ * @author fengshuonan
+ * @date 2020/8/24
+ */
+ public static void clearAesKey() {
+ CONTEXT_HOLDER.remove();
+ }
+
+}
diff --git a/kernel-d-security/security-spring-boot-starter/pom.xml b/kernel-d-security/security-spring-boot-starter/pom.xml
index 35fcd9f7b..7838ee498 100644
--- a/kernel-d-security/security-spring-boot-starter/pom.xml
+++ b/kernel-d-security/security-spring-boot-starter/pom.xml
@@ -45,6 +45,13 @@
7.0.2
+
+
+ cn.stylefeng.roses
+ security-sdk-request-encrypt-and-decode
+ 7.0.2
+
+