mirror of https://gitee.com/stylefeng/roses
commit
e2427c64b4
|
@ -77,6 +77,11 @@ public @interface PostResource {
|
|||
*/
|
||||
boolean requiredPermission() default true;
|
||||
|
||||
/**
|
||||
* 是否需要请求解密,响应加密 (true-需要,false-不需要)
|
||||
*/
|
||||
boolean requiredEncryption() default false;
|
||||
|
||||
/**
|
||||
* 是否是视图类型:true-是,false-否
|
||||
* 如果是视图类型,url需要以 '/view' 开头,
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
<module>security-sdk-captcha</module>
|
||||
<module>security-sdk-count</module>
|
||||
<module>security-sdk-xss</module>
|
||||
<module>security-sdk-request-encrypt-and-decode</module>
|
||||
<module>security-spring-boot-starter</module>
|
||||
</modules>
|
||||
|
||||
|
|
|
@ -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
|
||||
/**
|
||||
* 示例加密方法
|
||||
* <p>
|
||||
* requiredEncryption = true
|
||||
* </p>
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
```
|
|
@ -0,0 +1,49 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>cn.stylefeng.roses</groupId>
|
||||
<artifactId>kernel-d-security</artifactId>
|
||||
<version>7.0.2</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>security-sdk-request-encrypt-and-decode</artifactId>
|
||||
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15to18 -->
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk15to18</artifactId>
|
||||
<version>1.68</version>
|
||||
</dependency>
|
||||
|
||||
<!--安全模块的api-->
|
||||
<dependency>
|
||||
<groupId>cn.stylefeng.roses</groupId>
|
||||
<artifactId>security-api</artifactId>
|
||||
<version>7.0.2</version>
|
||||
</dependency>
|
||||
|
||||
<!--scanner api-->
|
||||
<dependency>
|
||||
<groupId>cn.stylefeng.roses</groupId>
|
||||
<artifactId>scanner-api</artifactId>
|
||||
<version>7.0.2</version>
|
||||
</dependency>
|
||||
|
||||
<!--web模块-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 =
|
||||
"MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDCJFZ8+ztB2z0r6BtptqvEo6fvW9lj1LsLlyaJNOYOjG8vyCLG2WV1upoEIbR+E/jyrEibDiOYCddtJvnWEOiFNFeYYi4ERC6EhbCHbyuitKIa47J7o9Ntg266nkJbDEyQP8BEeuzkK+D368lMdd2DdOtFvCJboaeIO9UY9yXR31OyFfkOCjqb1VmQsl8cmRUqaMA469517y4+BozXKa3ol7GNNyfq6IitaUOQpPO8Cr4dv1yP23P9DkUqjXtMXuhrhcLyV/GKYLMC8zCyX+Sap+HRxI2p6hb2zwtyNjSjth7FgkHf6OOnzxBvOpedQ1gxUbPQzZxguYBozYtXBa9Wt+zUcIHWj5aoaqNoGqX/hqlXKGp/vs/Loz7ZZSvXIqAN9FeNnWH3D17eOHehB2NKTfp9ugmYdcGcrDCh5zFblyxUmaP8zsI8/tfDwE8ZXj+syZEqMFFO/ld1xGecybyd3wR0r/YBpdmq7Q7aJGNCUUWAs1TM/56528sIDT4PFzOSmC9yvtLihC0P5MIWbWBZoL4qGjmWIxDs5XQvu0vw763PNsqahWP9+Dy4gbmWOqxTqsTlYVQKXXDS/wbPHVjPchdpEqZdOCbFk91o3edUD5gFP43cQpARNWU3rD7rn8cr/xmwHfp7GuWSTFSj7LS6aTQPMUVj/2LXHaRTvBc/MQIDAQABAoICAEmcX5K562j4CMSqGCLIGW7Qoq82A0I/+b/WSs1BWm1vwAS8/Lqq2TZ/T0B7yyT2y7CvtEPeY46VRLJlUdthw9gl1YS4zTve4khrLFjdxQzHMqPBa/5HSrY+XHCz6vL8wdb75RnSBhoprP4zz7qHAjuCzGY/hEN8Erqr/QufQh7Gb8SZYjp5lGlbxr7/cuK0BHt1BlVO0aWjz8PC1goLCp6jTbX+kMsX6iLeQ7kHYkcNR7KdySneiqcLjxwoUvTNE5EZQaaDw9i0+4sFzJQFmfct6oiP3yrq0FQ6gtuGRAVC234F+pY8hn0tHM0fyTbevwTMNsLYAxAFpfOW49tWE3nD4WxH2x/Xm4FUunfdJkMwsANBEnm4mz98whHW9SoH+ujuSvAFsBBwrUJcjCwn0DS1n9fqLrGBEtyVyh0GlbdUdHGZDqtbPCf7BhJpVVMYCKUP2fKPQAD13r+5rmv2wJllCfziIlMy3C5rUXcShDmPWdaY3b05r+QNIaIUgkNoblCO1sLsMgvL1Sber/z6lgSq/jxud3ja+JgwrA9jQBZQwOvddRUpi0VCSIDwgtsVzJNHsCQRnsHKUs5THglZO4QxcQX2yHXqlnyBm3VyxVGq3b8mrUdsnzhW2YV2e+HbnVN+Nx1cbexdedj3bsOGMUTFxW/FH97mUGus/HShsuYBAoIBAQDjbjQ2LqAaPdUe49vzUPxFBb4/R0m5jf1daP6tpuTZ3HOtR97M6amCIdyvLaw1AqIQlQ0QocPuw9LeWmeL0xYPqbXfrKi2/VXfPCdEgFn6POiuC7vFjVDSVZQDdSG4CWH4hr/CGSrBTqzbmXETYfXhPhOcQpw66eGfflnQk9myz9UpLRQ+E+ERKLu6OumhgvPeMgn2D2eMupIUIYrSrWKImw0f9mqNoylybK2AAcrUqMEJdoM7dHWXBefPGhAJL4CQv+we8TK8v0gaNz2pvGoCUtdSc+QBTk9+IKXeYyJNISpyvfcNvXGK+PgMjof+wkWgMZip9fMbAGDUSTtDuNzhAoIBAQDah6DdGzkmaGHi92PF2eMnuhPOGNQY14brZY3Pe3VL0GtmfqUXx/K4O4rtwtCWyShW5hv8y7vtkR0XQOtx6YRxeeIZCuikQVyeVcH4IJWHbrt9XyTeD/Lxm2ZETI6HO4AAdYHJo0xOKE33lKSKlsCO8R9SWLqY86EOfSE6nHdcRjlmEu1iilH2YZEliw/2/W9PW/KuPHcRs6uv+NGGP7KlwodCcvLWlf7b8RR2yMQ2CjzMrzyzqijuOCSFFu3hBcLVDIkElA7EwIAZ7nV6/3HVUIhDFFK1n8kXcMiSGiHIbpGT/wxnH90StXM99AGGe+YG31EIcS421x/jTPcByNxRAoIBAQCI7734MbKsmjZMVx4ELur2FDMsnpvBYcEAEUvm+uooUxhDaVa5QqeRdxoNUA60DFXQbi5jqULz7Gx2/TADfKF35NNhTfB33alqtClgkXebuDjRMrdoh2H2gxiPzGL1EJEwttGW6NhZdCmYP5dZ+E23xUzBdUnkHxZ+lfE2KQ+XHpRWKpJZnlaRolkGFJq/aL21N6PPyA6tKVjzTg7sMwF1BwasDA60IV2/S7hbrriVutYgAH+buM9kk2WzyRmGrldW0Hg3WTsXcoTTZBd4r72UkJSdTLIoJyKt6rJ0aHQqxKFuXPr4BuzqpGWWCevQdOC/R52IGFK8G0oyB7XrXM+BAoIBAD2QXhpMVBJk78bASURw+NS1UGUMi5wgA+uHJadhMY9VPRyX6yzC8LdEVwRakOcZ7ppko1fZka0A58AoUuw5jE1nt/G0KAw2OcCFimq7y0RnRrywNDO3LIsya2Isay7f7VSzxgenUJToN+ba4mwEwmTCuz84rgDvCd2KFPVtJRdC1WLTTDspmqOdowV/otTDWztxPPInKKg9BM5De8ulYE/geLiYp58ajL0rsscwEk7jHXPQnnpDItrRyEASUJvHQrdAm81FZM+7J5ummUQ4eLpOwMSdEhwG0uEerfKzF/deZvbZsIXQ7TgbFEdM2a0odIpVGYAWWp2qh1pC0YeYLbECggEBAL091vjMKLk7SBlpGKmwHS5Eo+94Fc6g1yC2+XbOsedo88inoEBlr52Ld+pKgGPGseJvT1Zf9WtcgVMvCcJ3Czc/uvRKoc9iAaWx1fPdZeuiojPQQDmbLMTgx4s4gp8Lk8uTiVoZ3piUgfESDEw+ukcTSTmMccrlGk5QXAvmtmAJzXMjHltldvOqF51E2Gu2lAcfKYy8aOdL4buavNEfHwKt9zIwnoP5EuSdfNwUkjTNe3YKZqXN8uodc7SvYYzIYBG4FwJPCiF8D+WSpXNr3MB+ff24d4CwQSNt5MNjeCjDuTE0VWf/aTyDL/454STc4gzyO5I9Bjwrs44WrS5krIA=";
|
||||
|
||||
/**
|
||||
* 模块名
|
||||
*/
|
||||
String ENCRYPTION_MODULE_NAME = "kernel-d-encryption";
|
||||
|
||||
/**
|
||||
* 异常枚举的步进值
|
||||
*/
|
||||
String ENCRYPTION_EXCEPTION_STEP_CODE = "29";
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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<String> 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();
|
||||
}
|
||||
|
||||
}
|
|
@ -45,6 +45,13 @@
|
|||
<version>7.0.2</version>
|
||||
</dependency>
|
||||
|
||||
<!--请求响应加密解密模块-->
|
||||
<dependency>
|
||||
<groupId>cn.stylefeng.roses</groupId>
|
||||
<artifactId>security-sdk-request-encrypt-and-decode</artifactId>
|
||||
<version>7.0.2</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
Loading…
Reference in New Issue