ResponseBodyAdvice和数据脱敏方案

7 篇文章 0 订阅

简介

ResponseBodyAdvice是Spring框架中的一个接口,用于在Controller方法返回结果之前对响应体进行处理。它可以对响应体进行加密、压缩、格式化等操作,从而优化程序的响应效率和用户体验。

RequestBodyAdvice和ResponseBodyAdvice增强器:点击跳转

spring的RequestBodyAdvice和ResponseBodyAdvice增强器

适用于路由器的请求和响应处理,比如验签,加解密,压缩解压,脱敏,格式化。

ResponseBodyAdvice实践

实现ResponseBodyAdvice接口

supports断言beforeBodyWrite是否执行。

@Slf4j
@ControllerAdvice
public class MyResponseBodyAdvice implements ResponseBodyAdvice {

    /**
     * 如果返回true,则beforeBodyWrite方法被执行
     *
     * @param returnType    the return type
     * @param converterType the selected converter type
     */
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        log.info("returnType:{},converterType:{}", returnType, converterType);
        if (Objects.equals(converterType, MappingJackson2HttpMessageConverter.class)) {
            log.info("消息类型正确");
            Method method = returnType.getMethod();
            assert method != null;
            ChangeBody annotation = method.getAnnotation(ChangeBody.class);
            //存在注解的就进行解析
            if (Objects.nonNull(annotation)) {
                log.info("注解正确");
                return true;
            }
        }
        return false;
    }

    /**
     * 作用在消息体HttpMessageConverter之后,body写操作之前
     *
     * @param body                  the body to be written
     * @param returnType            the return type of the controller method
     * @param selectedContentType   the content type selected through content negotiation
     * @param selectedConverterType the converter type selected to write to the response
     * @param request               the current request
     * @param response              the current response
     * @return the body that was passed in or a modified (possibly new) instance
     */
    @SneakyThrows
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                  Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        log.info("beforeBodyWrite:{},returnType:{},selectedContentType:{},selectedConverterType:{}", body,returnType,
                selectedContentType, selectedConverterType);
        Method method = returnType.getMethod();
        assert method != null;
        ChangeBody annotation = method.getAnnotation(ChangeBody.class);
        assert annotation != null;
        if (body instanceof MyResponse) {
            MyResponse res = (MyResponse) body;
            Object data = res.getData();
            changeField(data);
            log.info("替换后的结果 data:{}",data);
            res.setData(data);
        }
        return body;
    }

    private void changeField(Object data) throws IllegalAccessException {
        Class<?> aClass = data.getClass();
        //返回所有的字段,但是不包括父类的字段
        Field[] fields = aClass.getDeclaredFields();
        //返回公共的字段
        Field[] publicFields = aClass.getFields();
        if(fields.length == 0){
            return;
        }
        for (Field field : fields) {
            ChangeField f = field.getAnnotation(ChangeField.class);
            if (Objects.isNull(f)){
                continue;
            }
            log.info("替换的字段:{}",field);
            field.setAccessible(true);
            field.set(data,getFieldValue(f,field,data));
        }
    }

    private Object getFieldValue(ChangeField f,Field field,Object data) throws IllegalAccessException {
        log.info("判断执行替换");
        int sub = f.value();
        Object o = field.get(data);
        if (o instanceof String){
            String value = (String) o;
            if (Objects.isNull(value)){
                return o;
            }
            if (value.length() < sub){
                return o;
            }
            log.info("替换");
            //可以采用替换方法,正则表达式替换
            return value.substring(0,sub) + "**";
        }
        return o;
    }

}

注解用于标识

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ChangeBody {

}

接口使用

使用@ChangeBody进行区分是否执行增强,如果是统一增强,就不需要这样处理

    @ChangeBody
    @PostMapping("/getOne")
    public MyResponse<TestGetOneRes> getOne(@RequestBody TestGeOne in) {
        log.info("test/getOne,body:{}", in);
        return MyResponse.success(testServcie.getOne(in.getId()));
    }

自定义aop进行脱敏

spring的增强就是一种aop,如果无法满足需求,比如需要针对字段注解等,这个时候可以配合spring自带的增强或者自定义aop。

序列化脱敏

针对json的返回,可以使用序列化脱敏,灵活度更高

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值