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;
    }
}
相关推荐
Java女侠_9年实战8 分钟前
JVM调优“瞎调”——没分析GC日志,乱改堆内存参数导致OOM
后端
做个文艺程序员10 分钟前
流式输出(SSE)在 Spring Boot 中的实现【OpenClAW + Spring Boot 系列 第3篇】
java·spring boot·后端
逻辑驱动的ken10 分钟前
Java高频面试考点场景题09
java·开发语言·数据库·算法·oracle·哈希算法·散列表
小手cool11 分钟前
如何在Java中根据另一个配对集合对一个集合进行排序
java·开发语言
云烟成雨TD15 分钟前
Spring AI Alibaba 1.x 系列【28】Nacos Skill 管理中心功能说明
java·人工智能·spring
升鲜宝供应链及收银系统源代码服务16 分钟前
OMS 订单模块重构正式文档(一)---升鲜宝生鲜配送供应链管理系统
java·开发语言·重构·生鲜配送源代码·生鲜供应链源代码
Han.miracle21 分钟前
Redis 全套笔记:基础 API + 三大架构 + 缓存三大问题
java·windows·redis
zzb158023 分钟前
Fragment 生命周期深度图解:从 onAttach 到 onDetach 完整流程(面试必备)
android·java·面试·安卓
你有医保你先上28 分钟前
Elasticsearch Go 客户端
后端·elasticsearch·go
QC·Rex29 分钟前
Spring AI MCP Apps 实战:打造聊天与富 UI 融合的智能化应用
人工智能·spring·ui·spring ai·mcp