接口加解密

11/6/2022

# 一、背景与问题

有时候我们需要对一些关键接口进行数据加密,返回给前端,前端解密后,后端进行解密;

# 二、架构与思想

接口的加解密很容易想到 AOP,那么AOP又离不开 注解,所以我们定义了一个切面和两个注解(加解密各一个);

接口加密的模块叫做: jwe (JSON Web Encrypt)

# 三、具体使用

# 3.1、配置密钥key

密钥是JweUserKey,与用户相关的,这这样能保证每个用户的加密数据都不一样;

在使用的项目中配置config类,比如在sa-adminconfig包下面JweAspectConfig.java,具体配置如下:

@Configuration
public class JweAspectConfig {
    /**
     * 配置信息
     */
    @Bean
    public JweAspect jweConfig() {
        return new JweAspect((request -> {
            RequestUser requestUser = SmartRequestUtil.getRequestUser();
            JweUserKey userKey = new JweUserKey();
            userKey.setUserId(requestUser.getUserId());
            userKey.setUserName(requestUser.getUserName());
            userKey.setExtData(requestUser.getUserType().getValue().toString());
            return userKey;
        }));
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 3.2、加密@JweEncrypt

在需要加密的 controller方法上加上注解 @JweEncrypt

# 3.3、解密@JweDecrypt

在需要解密的 controller方法上加上注解 @JweDecrypt

# 四、实现原理

一共分两步:

  • 第一步: base64 转换
  • 第二步: 加密 或者 解密

# 4.1、AOP切面 解密

JweAspect.java


    @Before("@annotation(net.lab1024.sa.common.module.support.jwe.JweDecrypt)")
    public void before(JoinPoint joinPoint) {
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        JweDecrypt annotation = method.getAnnotation(JweDecrypt.class);
        if (annotation == null) {
            return;
        }
        Object[] params = joinPoint.getArgs();
        if (params == null) {
            return;
        }
        if (params.length == 0) {
            return;
        }
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        JweUserKey user = this.userFunction.apply(request);
        if (user == null) {
            return;
        }
        Boolean decryptParamFlag = params[0] instanceof DecryptData;
        if (!decryptParamFlag) {
            return;
        }
        DecryptData decryptData = (DecryptData) params[0];
        String data = decryptData.getData();
        log.info("解密前数据:{}", data);

        String key = SecureUtil.md5(String.format(MD5_SALT_FORMAT, user.getUserId()));
        log.info("解密KEY数据:{}", key);
        //初始化向量是16位长度
        String iv = key.substring(0, 16);
        //解密
        AES aes = new AES(Mode.CTS, Padding.PKCS5Padding, key.getBytes(), iv.getBytes());
        data = aes.decryptStr(data);
        log.info("解密后数据:{}", data);
        //base64解码
        data = new String(Base64Utils.decodeFromString(data));
        log.info("base64解码后数据:{}", data);
        decryptData.setData(data);
    }
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

# 4.2、AOP切面 加密

JweAspect.java

 @AfterReturning(returning = "object", pointcut = "@annotation(net.lab1024.sa.common.module.support.jwe.JweEncrypt)")
    public void afterReturning(JoinPoint joinPoint, Object object) {
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        JweEncrypt annotation = method.getAnnotation(JweEncrypt.class);
        if (annotation == null) {
            return;
        }
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        JweUserKey user = this.userFunction.apply(request);
        if (user == null) {
            return;
        }
        try {
            ResponseDTO responseDTO = (ResponseDTO) object;
            Object data = responseDTO.getData();
            if (data == null) {
                return;
            }
            String jsonData = JSON.toJSONString(data, SerializerFeature.DisableCircularReferenceDetect);
            log.info("JSON 原数据:{}", jsonData);
            //base64编码
            jsonData = Base64Utils.encodeToString(jsonData.getBytes("utf-8"));
            log.info("JSON Base64数据:{}", jsonData);
            //加密秘钥
            String key = SecureUtil.md5(String.format(MD5_SALT_FORMAT, user.getUserId()));
            log.info("JSON MD5 KEY数据:{}", key);
            //初始化向量是16位长度
            String iv = key.substring(0, 16);
            //AES 加密
            AES aes = new AES(Mode.CTS, Padding.PKCS5Padding, key.getBytes(), iv.getBytes());
            data = aes.encryptBase64(jsonData);
            log.info("JSON ASE 加密数据:{}", jsonData);
            responseDTO.setData(jsonData);
        } catch (Exception e) {
            log.error(e.getMessage(),e);
            return;
        }
    }
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

# 联系我们

1024创新实验室-主任:卓大 (opens new window),混迹于各个技术圈,研究过计算机,熟悉点 java,略懂点前端。
1024创新实验室(河南·洛阳) (opens new window) 致力于成为中原领先、国内一流的技术团队,以技术创新为驱动,合作各类项目(软件外包、技术顾问、培训等等)。

加 主任 “卓大” 微信
拉你入群,一起学习
关注 “小镇程序员”
分享代码与生活、技术与赚钱
请 “1024创新实验室” 喝咖啡
支持我们的开源与分享

告白气球 (钢琴版)
JESSE T