原创

如何优雅的对用户敏感信息进行加密

温馨提示:
本文最后更新于 2024年03月09日,已超过 319 天没有更新。若文章内的图片失效(无法正常加载),请留言反馈或直接联系我

在当今数字时代,个人隐私保护和企业对用户敏感信息的处理是社会高度关注的问题。现实情况表明,随着技术的发展和数据量的激增,个人信息的收集、存储、处理和传输活动变得更加频繁,这也带来了隐私泄露和信息安全的风险

那么今天我们来解决一个非常实用的问题:对客户敏感信息如手机号、证件号、银行卡号等等进行加密处理

需求很简单,前端来请求我们用户信息时将其中部分敏感信息用*来替换即可,基础实现就是每个人都对自己接口内敏感信息做个加密处理,这样当然也是可以实现需求的,但很显然这是一个系统共性需求,而且我们希望系统内所有敏感信息的加密方式都统一,不因开发人员喜好而出现多版本,而且也不应该在一个共性需求上让大家都来把这个工作来做一遍。

通过以上分析,我们很容易就想到了我们的AOP技术,没错,今天我们就用面向切面编程的思想来解决这个需求,如果不熟悉和小伙伴可以看我们前面的文章基于Spring AOP实现自定义注解

1.注解定义

首先我们实现一个自定义加密注解,告知Spring

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
public @interface Desensitization {
    String type() default "";

    String PHONE = "PHONE";
    String ID_CARD = "ID_CARD";
    String BANK_CARD = "BANK_CARD";
}

2.接口定义

定义一个接口,接口唯一的任务就是对需要进行加密的原数据进行加密处理

public interface DesensitizationProcessor {
    String process(String data);
}

3.加密

定义一个枚举类,定义要进行加密的数据类型,并针对不同数据实现其加密方法

public enum DesensitizationEnum implements DesensitizationProcessor {
    PHONE {
        @Override
        public String process(String phone) {
            if (StringUtils.isNotBlank(phone) && phone.length() == 11) {
                return phone.substring(0, 3).concat("****").concat(phone.substring(phone.length() - 4));
            }
            return phone;
        }
    },
    ID_CARD {
        @Override
        public String process(String idCard) {
            if (StringUtils.isNotBlank(idCard) && idCard.length() >= 15) {
                return idCard.substring(0, 6).concat("*****").concat(idCard.substring(idCard.length() - 4));
            }
            return idCard;
        }
    },
    BANK_CARD {
        @Override
        public String process(String bankCard) {
            if (StringUtils.isNotBlank(bankCard) && bankCard.length() > 10) {
                return bankCard.substring(0, 4).concat(" **** ").concat(bankCard.substring(bankCard.length() - 4));
            }
            return bankCard;
        }
    };

    public static DesensitizationEnum getDesensitizationEnum(String type) {
        DesensitizationEnum[] values = DesensitizationEnum.values();
        for (DesensitizationEnum desensitization : values) {
            if (desensitization.name().equals(type)){
                return desensitization;
            }
        }
        return null;
    }
}

4.切面逻辑

编写切面逻辑,对指定数据进行加密处理

@Slf4j
@Aspect
@Component
public class DesensitizationAspect {
    @Around("@annotation(desensitization)")
    public Object desensitization(ProceedingJoinPoint point, Desensitization desensitization) {
        Object returnValue = null;
        try {
            returnValue = point.proceed();
            if (Objects.isNull(returnValue)) {
                return null;
            }
            Class<?> aClass = returnValue.getClass();
            Field[] declaredFields = aClass.getDeclaredFields();
            for (Field field : declaredFields) {
                Desensitization fieldDesensitization = field.getAnnotation(Desensitization.class);
                if (Objects.isNull(fieldDesensitization)) {
                    continue;
                }
                String type = fieldDesensitization.type();
                if (StringUtils.isBlank(type)) {
                    continue;
                }
                DesensitizationEnum desensitizationEnum = DesensitizationEnum.getDesensitizationEnum(type);
                if (Objects.isNull(desensitizationEnum)) {
                    continue;
                }
                field.setAccessible(true);
                Object value = field.get(returnValue);
                if (Objects.nonNull(value) && value instanceof String) {
                    field.set(returnValue, desensitizationEnum.process((String) value));
                }
            }
        } catch (Throwable e) {
            log.error("敏感信息加密异常", e);
        }

        return returnValue;
    }
}

5.使用

定义用户类

@Data
public class UserBo {
    private Long id;
    @Desensitization(type = Desensitization.PHONE)
    private String phone;
    @Desensitization(type = Desensitization.ID_CARD)
    private String idCardNo;
    @Desensitization(type = Desensitization.BANK_CARD)
    private String bankCardNo;
}

编写Controller给前端调用

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
    @Desensitization
    @GetMapping("/info/{id}")
    public UserBo getUser(@PathVariable(name = "id") Long id){
        UserBo userBo = new UserBo();
        userBo.setId(id);
        userBo.setPhone("18088888888");
        userBo.setIdCardNo("340888199909092999");
        userBo.setBankCardNo("6217000179872312231");
        return userBo;
    }
}

6.接口访问

结果
可以看到,返回的数据已经做了加密处理,后续其它接口需要加密时只需要在对应加密字段上添加我们的自定义注解并标注字段类型即可,这样就不需要每个人都来对加密字段都实现加密处理啦~~~

正文到此结束
本文目录