Spring体系下解决请求统一加解密之ResponseBodyAdvice和RequestBodyAdvice

在日常写项目中经常一般正规的项目都需要将信息加密后返回前端,前端进行解密后再展示出来给用户,这样做的目的无一不是为了安全,在Java开发中,如何简单快速的完成这个功能呢,这里就需要用到这两个接口ResponseBodyAdvice和RequestBodyAdvice。

ResponseBodyAdvice是 spring 4.1 新加入的一个接口,在消息体被HttpMessageConverter写入之前允许Controller 中 @ResponseBody修饰的方法调整响应中的内容,比如进行相应的加密或者进行统一处理返回值/响应体。【同样RequestBodyAdvice也是在 sping 新加入的一个接口,它可以使用在 @RequestBody 或 HttpEntity 修饰的参数读取之前进行参数的处理,比如进行参数的解密】 通俗来讲就是在数据返回前端之前可以通过这个ResponseBodyAdvice接口来将响应中的数据进行操作后再返回前端。接下来直接上代码

1.首先需要自己写一个类来实现ResponseBodyAdvice这个接口,然后重写方法

2.supports这个方法返回参数是布尔值,返回false则代表不走到beforeBodyWrite这个方法,返回true则代表走到这个方法。因此可以在这里进行检查方法是否有我们自己定义的注解,比如我的代码就是检查了方法参数上有没有EncryptBody这个注解,有的话就会去进行beforeBodyWrite方法的执行。

3.beforeBodyWrite这个方法中的参数body就是你返回前端的所有body,在这里可以判断参数类型,并对参数进行加密操作。

java 复制代码
@Component
@ControllerAdvice
public class EncryptBodyAdvice implements ResponseBodyAdvice {
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return returnType.hasMethodAnnotation(EncryptBody.class);
    }

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if (body instanceof AjaxResult) {
            //AjaxResult类型加密
            AjaxResult ajaxResult =(AjaxResult) body;
            ajaxResult.put("encrypt",true);

            Object bodyData = ajaxResult.get("data");
            ajaxResult.put("data",handleENCData(bodyData));
            return ajaxResult;
        } else if (body instanceof TableDataInfo) {
            //TableDataInfo类型加密
            TableDataInfo tableDataInfo =(TableDataInfo) body;
            tableDataInfo.setEncrypt(true);

            if (!CollectionUtils.isEmpty(tableDataInfo.getRows())){
                tableDataInfo.setRows(handleENCData(tableDataInfo.getRows()));
                return tableDataInfo;
            }

        }
        return body;
    }

    /**
     * 处理加密数据
     *
     * @param data 数据
     * @return {@link Object}
     */
    private Object handleENCData(Object data){
        if (Objects.isNull(data)){
            return data;
        }
        //自动关流
        try {

            return Base64.encode(objectMapper.writeValueAsString(data));
        }catch (Exception e){
            e.printStackTrace();
        }
        return data;
    }


    /**
     * 处理加密数据
     *
     * @param data 数据
     * @return {@link List}<{@link Object}>
     */
    private List<Object> handleENCData(List data){
        if (Objects.isNull(data)){
            return data;
        }
        try {
            List<Object> newData = new ArrayList<>();
            for (Object datum : data) {
                //base64加密
                newData.add(Base64.encode(objectMapper.writeValueAsString(datum)));
            }
            return newData;
        }catch (Exception e){
            e.printStackTrace();
        }
        return data;
    }

    //public static void main(String[] args) {
    //    try {
    //        String s="eyJjb2xsZWdlSWQiOiIzIiwic3RhZmZJZCI6IjEiLCJkZWxGbGFnIjoiMCIsInBpY3R1cmUiOiJodHRwczovL2NhYnMubXllYmtqLmNvbS9jYWJzaW1ncy9jYWJzLzIwMjQvMDEvMDkvMzMuanBnIiwibmFtZSI6IuiuuOW8uiIsIm51bWJlciI6IjEwMDAwIiwicGhvbmUiOiIiLCJzZXgiOiIwIiwiZGF0ZUJpcnRoIjoiMTk2OC0wNi0wMSIsImlkQ2FyZCI6IiIsInN0YWZmU3RhdHVzIjoiMCIsInRpdGxlIjoiMCIsImpvYiI6IjkiLCJjYXRlZ29yeSI6IjMiLCJ0ZWFjaGluZ0lkTmFtZSI6Ii0iLCJkZXB0TmFtZSI6IueOr+Wig+S4juWcn+acqOW3peeoi+WtpumZoiwg5Zyw6LSo5bel56iL57O7IiwidGVhY2hKb2JWYWx1ZSI6IuS4k+S4mui0n+i0o+S6uiIsImNhdGVnb3J5VmFsdWUiOiLlhbbku5YiLCJ0aXRsZVZhbHVlIjoi5pWZ5o6IIiwic3RhZmZTdGF0dXNWYWx1ZSI6IuWcqOiBjCIsInNleFZhbHVlIjoi55S3IiwiZWR1Y2F0aW9uIjoiMyJ9";
    //        System.out.println(new String(Base64.decode(s)));
    //        //System.out.println(Base64.encode("123456"));
    //    } catch (Exception e){
    //
    //    }
    //}
}

同理RequestBodyAdvice操作也类似,这里不再举例

java 复制代码
@Component
@ControllerAdvice
public class DecryptBodyAdvice implements RequestBodyAdvice {
    @Override
    public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        return false;
    }

    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
        return null;
    }

    @Override
    public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        return null;
    }

    @Override
    public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        return null;
    }
}
相关推荐
ServBay8 分钟前
AI Gateway 是什么?为什么每个平台都在做
后端·aigc·ai编程
SamDeepThinking21 分钟前
Vibe Coding最重要的是Spec
后端·程序员·ai编程
掘金_答案24 分钟前
上线那天,一个 ConcurrentHashMap 差点送走我的 AI 客服——3 天排查 JVM 血泪史
java·后端·架构
妙码生花29 分钟前
从 PHP 到 AI + Golang,程序员自救转型手记(三十三):权限规则管理器
后端·go·gin
MindUp1 小时前
企业网盘权限模型解析:多层级访问控制与审计能力选型指南
java·linux·运维
Kim_wang1 小时前
agent项目部署流程
人工智能·后端
NG4771 小时前
【软件设计与体系结构】-策略设计模式
java·设计模式·软件工程
程序员天天困2 小时前
优雅记录操作日志:从注解到 SpEL 的全链路实践与开源方案对比
java·后端
战血石LoveYY2 小时前
Integer类型超限,导致数据异常
java·算法
饼干哥哥3 小时前
Vibe Coding 出海首月收割 100+用户爆赚美金,怎么做?
后端·架构·代码规范