springboot接口数据编解码&脱敏

添加依赖

<dependency>
    <groupId>com.github.ulisesbocchio</groupId>
    <artifactId>jasypt-spring-boot-starter</artifactId>
    <version>3.0.4</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.7.22</version>
</dependency>

定义注解

作用于方法上,标记参数需要做编解码

package clown.annotation;

import org.springframework.stereotype.Component;
import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface EncryptMethod {
}

作用于字段上,标记字段需要做编解码,以及是否需要脱敏展示

package clown.annotation;

import org.springframework.stereotype.Component;
import java.lang.annotation.*;

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface EncryptField {
    // 解码后是否脱敏
    boolean isDesensitized() default false;
    // 脱敏开始位置
    int desensitizedBeginIndex() default 0;
    // 脱敏长度
    int desensitizedLength() default 0;
    // 脱敏显示字符
    char desensitizedDisplayChar() default '*';
}

加密配置

application.properties 中配置jasypt,也可以使用其他加密工具包替代,或手动加密

jasypt.encryptor.password=PtxbCPZWFfhPjtsvhYo7LA==
jasypt.encryptor.algorithm=PBEWithMD5AndDES
jasypt.encryptor.iv-generator-classname=org.jasypt.iv.NoIvGenerator

AOP处理器

package clown.aop;

import clown.annotation.EncryptField;
import clown.domain.CommRes;
import cn.hutool.core.util.StrUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.jasypt.encryption.StringEncryptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;

@Aspect
@Component
public class EncryptMethodHandler {
    @Autowired
    private StringEncryptor stringEncryptor;

    @Pointcut("@annotation(clown.annotation.EncryptMethod)")
    public void encryptMethodPointCut() {}

    @Around("encryptMethodPointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] args = joinPoint.getArgs();
        // 加密
        encrypt(args);
        // 业务处理
        Object result = joinPoint.proceed(args);
        // 解密
        decrypt(result);
        return result;
    }

    private void encrypt(Object[] args) throws IllegalAccessException {
        if (args.length > 0) {
            for (Object obj: args) {
                handle(obj, EncryptConstant.ENCRYPT);
            }
        }
    }

    private void decrypt(Object result) throws IllegalAccessException {
        if (result instanceof CommRes) {
        	// 处理通用应答包装类
            handle(((CommRes) result).getData(), EncryptConstant.DECRYPT);
        } else {
            handle(result, EncryptConstant.DECRYPT);
        }
    }

    public void handle(Object obj, String type) throws IllegalAccessException {
        if (obj == null) {
            return;
        }

        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            boolean isEncrypt = field.isAnnotationPresent(EncryptField.class);
            if (!isEncrypt) {
                continue;
            }

            field.setAccessible(true);
            Object value = field.get(obj);
            if (value instanceof String) {
                if (EncryptConstant.ENCRYPT.equals(type)) {
                    field.set(obj, stringEncryptor.encrypt((String)value));
                } else if (EncryptConstant.DECRYPT.equals(type)) {
                    String decrypt = stringEncryptor.decrypt((String)value);
                    EncryptField encryptFieldAnnotation = field.getAnnotation(EncryptField.class);
                    if (encryptFieldAnnotation.isDesensitized()) {
                        int beginIndex = encryptFieldAnnotation.desensitizedBeginIndex();
                        int length = encryptFieldAnnotation.desensitizedLength();
                        if (beginIndex + length > decrypt.length()) {
                            throw new RuntimeException("脱敏配置异常");
                        }
                        field.set(obj, StrUtil.replace(decrypt, beginIndex, beginIndex+length, encryptFieldAnnotation.desensitizedDisplayChar()));
                    } else {
                        field.set(obj, decrypt);
                    }
                }
            }
        }
    }

    interface EncryptConstant {
        String ENCRYPT = "encrypt";

        String DECRYPT = "decrypt";
    }
}

通用应答包装类

package clown.domain;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class CommRes {
    private int code;
    private String msg;
    private Object data;

    public static CommRes success() {
        return success(null);
    }

    public static CommRes success(Object data) {
        return new CommRes().setCode(0).setMsg("success").setData(data);
    }

    public static CommRes fail(String msg) {
        return new CommRes().setCode(-1).setMsg(msg);
    }

    public int getCode() {
        return code;
    }

    public CommRes setCode(int code) {
        this.code = code;
        return this;
    }

    public String getMsg() {
        return msg;
    }

    public CommRes setMsg(String msg) {
        this.msg = msg;
        return this;
    }

    public Object getData() {
        return data;
    }

    public CommRes setData(Object data) {
        this.data = data;
        return this;
    }

    public String toJsonString() throws JsonProcessingException {
        return new ObjectMapper().writeValueAsString(this);
    }
}

测试代码

请求参数

package clown.domain;

import clown.annotation.EncryptField;

public class LoginVO {
    @EncryptField(isDesensitized = true, desensitizedLength = 2, desensitizedBeginIndex = 2, desensitizedDisplayChar = '*')
    private String username;
    @EncryptField(isDesensitized = false, desensitizedLength = 2, desensitizedBeginIndex = 5, desensitizedDisplayChar = '$')
    private String password;

    public String getUsername() {
        return username;
    }

    public LoginVO setUsername(String username) {
        this.username = username;
        return this;
    }

    public String getPassword() {
        return password;
    }

    public LoginVO setPassword(String password) {
        this.password = password;
        return this;
    }
}

控制器

package clown.controller;

import clown.annotation.EncryptMethod;
import clown.domain.CommRes;
import clown.domain.LoginVO;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class LoginController {
    
    // 使用通用应答包装,方法执行完成后,aop会自动进行解码和脱敏处理
    @RequestMapping(value = "login")
    @EncryptMethod
    @ResponseBody
    public CommRes login(@RequestBody LoginVO loginVO) {
	    System.err.println(loginVO.getUsername()); // 打印加密后的字符串
        System.err.println(loginVO.getPassword()); // 打印加密后的字符串
        return CommRes.success(loginVO);
    }
    
    // 不使用通用应答包装,方法执行完成后,aop会自动进行解码和脱敏处理
	@RequestMapping(value = "login")
    @EncryptMethod
    @ResponseBody
    public LoginVO login(@RequestBody LoginVO loginVO) {
   		System.err.println(loginVO.getUsername()); // 打印加密后的字符串
        System.err.println(loginVO.getPassword()); // 打印加密后的字符串
        return loginVO
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ARINC 429是一种常见的数据总线协议,用于在航空电子设备中传输数据。其中,BNR(Binary Coded Decimal)是一种编码方式,用于将十进制数转换为二进制数进行传输。 在编程实现BNR数据编解码之前,需要先了解BNR的编码规则。BNR将十进制数转换为二进制数时,先将其转换为BCD码(每个十进制数用4位二进制数表示),然后将BCD码转换为二进制数。例如,十进制数19的BCD码为0001 1001,转换为二进制数为10011。 接下来是一个简单的C语言实现BNR编码的示例: ```c void encode_bnr(int num, int* bnr) { int bcd[8] = {0}; // 存储BCD码的数组 int i, j; // 将十进制数转换为BCD码 for (i = 0; num > 0; i++) { bcd[i] = num % 10; num /= 10; } // 将BCD码转换为二进制数 for (i = 0, j = 0; i < 8; i += 2, j++) { bnr[j] = (bcd[i+1] << 3) + (bcd[i] & 0x07); } } int main() { int num = 19; int bnr[4] = {0}; int i; encode_bnr(num, bnr); // 输出编码后的结果 for (i = 0; i < 4; i++) { printf("%02X ", bnr[i]); } printf("\n"); return 0; } ``` 上述代码中,encode_bnr函数将十进制数num编码为BNR格式,存储在bnr数组中。对于本例中的十进制数19,编码后的结果为13 00 00 00(以十六进制表示)。 类似地,可以实现BNR解码的函数。在解码时,将二进制数转换为BCD码,再将BCD码转换为十进制数即可。以下是一个简单的C语言实现BNR解码的示例: ```c int decode_bnr(int* bnr) { int bcd[8] = {0}; // 存储BCD码的数组 int num = 0; int i, j; // 将二进制数转换为BCD码 for (i = 0, j = 0; i < 8; i += 2, j++) { bcd[i] = bnr[j] & 0x07; bcd[i+1] = bnr[j] >> 3; } // 将BCD码转换为十进制数 for (i = 7; i >= 0; i--) { num = num * 10 + bcd[i]; } return num; } int main() { int bnr[4] = {0x13, 0x00, 0x00, 0x00}; int num; num = decode_bnr(bnr); // 输出解码后的结果 printf("%d\n", num); return 0; } ``` 上述代码中,decode_bnr函数将BNR格式的数据解码为十进制数。对于本例中的BNR数据13 00 00 00,解码后的结果为19。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值