• SpringBoot 接口数据加解密


    xx项目有于安全问题,需要对接口整体进行加密处理,我们怎么处理呢。

    和产品、前端讨论需求后,梳理了相关技术方案,主要的需求点如下:

    • 尽量少改动,不影响之前的业务逻辑;

    • 考虑到时间紧迫性,可采用对称性加密方式,服务需要对接安卓、IOS、H5三端,另外考虑到H5端存储密钥安全性相对来说会低一些,故分针对H5和安卓、IOS分配两套密钥;

    • 要兼容低版本的接口,后面新开发的接口可不用兼容;

    • 接口有GET和POST两种接口,需要都要进行加解密;

    需求解析:

    • 服务端、客户端和H5统一拦截加解密,网上有成熟方案,也可以按其他服务中实现的加解密流程来搞;

    • 使用AES放松加密,考虑到H5端存储密钥安全性相对来说会低一些,故分针对H5和安卓、IOS分配两套密钥;

    • 本次涉及客户端和服务端的整体改造,经讨论,新接口统一加 /secret/ 前缀来区分

    那我们可以使用 @ControllerAdvice + RequestBodyAdvice/ResponseBodyAdvice 轻松实现

    @ControllerAdvice / @RestControllerAdvice 区别?

    @ControllerAdvice + @ExceptionHandler来实现全局异常捕获;陌生在于你除了copy代码时看到过外,自己似乎从来没有真正使用过它。
    在前面关于@ModelAttribute和@InitBinder 的相关文章中其实和这个注解是打过照面的:在此注解标注的类上使用@InitBinder等注解可以使得它对"全局"生效实现统一的控制。本文将把@ControllerAdvice此注解作为重点进一步的去了解它的使用以及工作机制。

    此类的命名是很有信息量的:Controller的Advice通知。关于Advice的含义,熟悉AOP相关概念的同学就不会陌生了,因此可以看到它整体上还是个AOP的设计思想,只是实现方式不太一样而已。
     

    @ControllerAdvice使用AOP思想可以这么理解:此注解对目标Controller的通知是个环绕通知,织入的方式是注解方式,增强器是注解标注的方法。如此就很好理解@ControllerAdvice搭配@InitBinder/@ModelAttribute/@ExceptionHandler起到的效果喽~

    官方doc说它可以和如上我指出的三个注解的一起使用。关于它的使用我总结有如下注意事项:

    @ControllerAdvice只需要标注上即可,Spring MVC会在容器里自动探测到它(请确保能被扫描到,否则无效哦~)
    若有多个@ControllerAdvice可以使用@Order或者Ordered接口来控制顺序
    basePackageClasses属性最终也是转换为了basePackages拿去匹配的

    RequestBodyAdvice/ResponseBodyAdvice
    顾名思义,它们和@RequestBody和@ResponseBody有关,ResponseBodyAdvice是Spring4.1推出的,另外一个是4.2后才有。它哥俩和@ControllerAdvice一起使用会有很好的化学反应

    RequestBodyAdvice

    官方解释为:允许body体转换为对象之前进行自定义定制;也允许该对象作为实参传入方法之前对其处理。

    1. public interface RequestBodyAdvice {
    2. // 第一个调用的。判断当前的拦截器(advice是否支持)
    3. // 注意它的入参有:方法参数、目标类型、所使用的消息转换器等等
    4. boolean supports(MethodParameter methodParameter, Type targetType, Class> converterType);
    5. // 如果body体木有内容就执行这个方法(后面的就不会再执行喽)
    6. Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class> converterType);
    7. // 重点:它在body被read读/转换**之前**进行调用的
    8. HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class> converterType) throws IOException;
    9. // 它在body体已经转换为Object后执行。so此时都不抛出IOException了嘛~
    10. Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class> converterType);
    11. }

    它的内置实现有这些:

    RequestResponseBodyAdviceChain比较特殊,放在后面重点说明。RequestBodyAdviceAdapter没啥说的,因此主要看看JsonViewRequestBodyAdvice这个实现。

    JsonViewRequestBodyAdvice
    Spring MVC的内置实现,它支持的是Jackson的com.fasterxml.jackson.annotation.@JsonView这个注解,@JsonView一般用于标注在HttpEntity/@RequestBody上,来决定处理入参的哪些key。
    该注解指定的反序列视图将传递给MappingJackson2HttpMessageConverter,然后用它来反序列化请求体(从而做对应的过滤)。
     

    1. // @since 4.2
    2. public class JsonViewRequestBodyAdvice extends RequestBodyAdviceAdapter {
    3. // 处理使用的消息转换器是AbstractJackson2HttpMessageConverter类型
    4. // 并且入参上标注有@JsonView注解的
    5. @Override
    6. public boolean supports(MethodParameter methodParameter, Type targetType, Class> converterType) {
    7. return (AbstractJackson2HttpMessageConverter.class.isAssignableFrom(converterType) &&
    8. methodParameter.getParameterAnnotation(JsonView.class) != null);
    9. }
    10. // 显然这里实现的beforeBodyRead这个方法:
    11. // 它把body最终交给了MappingJacksonInputMessage来反序列处理消息体
    12. // 注意:@JsonView能处理这个注解。也就是说能指定把消息体转换成指定的类型,还是比较实用的
    13. // 可以看到当标注有@jsonView注解后 targetType就没啥卵用了
    14. @Override
    15. public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter methodParameter, Type targetType, Class> selectedConverterType) throws IOException {
    16. JsonView ann = methodParameter.getParameterAnnotation(JsonView.class);
    17. Assert.state(ann != null, "No JsonView annotation");
    18. Class[] classes = ann.value();
    19. // 必须指定class类型,并且有且只能指定一个类型
    20. if (classes.length != 1) {
    21. throw new IllegalArgumentException("@JsonView only supported for request body advice with exactly 1 class argument: " + methodParameter);
    22. }
    23. // 它是一个InputMessage的实现
    24. return new MappingJacksonInputMessage(inputMessage.getBody(), inputMessage.getHeaders(), classes[0]);
    25. }
    26. }

    ResponseBodyAdvice

    它允许在@ResponseBody/ResponseEntity标注的处理方法上在用HttpMessageConverter在写数据之前做些什么。

    1. // @since 4.1 泛型T:body类型
    2. public interface ResponseBodyAdvice {
    3. boolean supports(MethodParameter returnType, Class> converterType);
    4. @Nullable
    5. T beforeBodyWrite(@Nullable T body, MethodParameter returnType, MediaType selectedContentType, Class> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response);
    6. }

    @JsonView的使用:它可以放入参时接收指定的字段;也可以让返回值中敏感字段(如密码、盐值等)不予返回,可做到非常灵活的配置和管理,实现一套代码多处使用的目的,提高集成程度

    需要注意的是:xxxBodyAdvice虽然使用方便,但是它的普适性还是没有HandlerInterceptor那么强的,下面我列出使用它的几点局限/限制

  • 相关阅读:
    [CVE-2016-4437] Apache Shiro 安全框架反序列化漏洞复现与原理详细分析
    flutter在导航栏处实现对两个列表的点击事件
    mac 安装 homebrew
    SQL Server 索引结构
    C++设计模式 - 总结
    Kotlin的对象表达式(Object expressions)
    git解决冲突会带上另外一方不相关代码
    图的学习,深度和广度遍历
    MODBUS-RTU从站通信(SMART PLC作为MODBUS-RTU从站)
    JAVA代码审计-XSS漏洞分析
  • 原文地址:https://blog.csdn.net/u010581811/article/details/127436584