goupan
2024-04-03 5506e9a45e717ffcb67ec313b5a4e8206d9b3a39
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
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
@SuppressWarnings("all")
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;
    }
}