通过RequestBodyAdvice和自定义注解,实现加密参数自动解密

RequestBodyAdvice接口

它是SpringMVC提供的一个接口,类注释如下

允许在请求体被读取并转换为Object之前对请求进行定制,也允许在结果对象作为@RequestBody或HttpEntity方法参数传递给控制器方法之前对其进行处理。 该接口的实现可以直接注册到RequestMappingHandlerAdapter,或者更有可能使用@ControllerAdvice注释,在这种情况下它们会被自动检测。

它提供了四个方法

  • supports:首次调用,判断这个拦截器是否适用这次请求,返回boolean
  • beforeBodyRead:在转换至Controller参数对象之前调用,加工请求头和请求体
  • afterBodyRead:在转换至Controller参数对象之后调用,处理这个对象
  • handleEmptyBody:当参数为空时调用,可以返回请求体,也可以返回null正常触发Body为空的报错

实现方式

我们的思路是这样的,首先自定义一个注解@Encrypt,用在被@RequestBody标记的参数上。

然后我们实现RequestBodyAdvice接口,首先实现supports接口,通过判断是否标注了我们的注解,来决定是否进行解密操作

  @Override  
   public boolean supports(
      MethodParameter methodParameter, Type type, 
      Class<? extends HttpMessageConverter<?>> aClass) {
        return methodParameter.hasParameterAnnotation(Encrypt.class);
  }  

然后,我们在beforeBodyRead方法中,实现我们解密的核心操作

    @Override  
    public HttpInputMessage beforeBodyRead(
      HttpInputMessage httpInputMessage, 
      MethodParameter methodParameter, Type type, 
      Class<? extends HttpMessageConverter<?>> aClass) throws IOException {

        return new HttpInputMessage() {
            @Override
            public InputStream getBody() throws IOException {
                logger.info("请求头参数:"+ httpInputMessage.getHeaders());
                logger.info("在此处去掉请求参数外层data");
                String body = IOUtils.toString(httpInputMessage.getBody());
                JSONObject jasonObject = JSONObject.parseObject(body);
                String content = (String)jasonObject.get("data");
                //进行解密操作
                String after = null;
                try {
                    DESUtils desUtils = new DESUtils(desKey);
                    after = desUtils.decryptString(content);
                } catch (Exception e) {
                    logger.error("解密失败");
                }
                return new ByteArrayInputStream
                        (after.getBytes(StandardCharsets.UTF_8));

            }
  
            @Override  
            public HttpHeaders getHeaders() {
                return httpInputMessage.getHeaders();  
            }  
        };  
    }  

afterBodyRead接口直接返回Object,不做任何其他处理

根据类文档说明,要向让这个自定义的RequestBodyAdvice起作用,我们可以给它添加上@ControllerAdvice注解,他就可以自动注册到Spirng容器,而后注册到RequestMappingHandlerAdapter

至此,我们就实现了我们的功能。

思考

我们可以看到,在SpringMVC中有很多类似的Adapter,它们大部分都为我们提供了简单的扩展方式。通过探究这些接口在系统中生效的原理,也是我们看SpringMVC源码很好的切入点

posted @ 2021-11-25 19:30  XmCui  阅读(1026)  评论(0编辑  收藏  举报