微服务巧用Aop,使用RequestBodyAdvice对请求参数加密,项目全局增强Api接口安全性

大家好,我是程序员大猩猩。

在我们日常开发中,通常不会考虑到Api的安全性,但是在运维部署时,如果是小公司,大可能的配置ssl文件是免费的,安全性并不是很高,市场上有很多的工具可以简单的进行破解,这大大的增加了我们Api接口的风险值

如果不管不问,我们的Api接口就像在互联网上裸奔一样,专业破解方就像看我们的API没穿裤衩子一样,随意的更改我们的请求与回放。

当领导找到我们时,是不是内心遭受了百万暴击一样,满腹在骂娘!~~

我TM我的接口没有一点毛病,有攻击就加强服务器的安全组件,干什么说我技术不行,CAO~~~~

心里骂了半天,但是又有什么办法,领导又不懂代码,我们不是还得撸起袖子搞点安全系数高的代码来增强我们的Api。

那么如何更改呢?

1. 前端Json块使用约定俗成的加密盐进行对称加密。

2. 后端进行解密操作。

3. 后端对请求的返回Json块进行加密

4. 前端进行解密操作。

注:双方一定要约定一套有加密盐的对称加密方式最佳哦!~~

接下来,我们来完成后端部分的全局解密方法。

一、RequestBodyAdvice

RequestBodyAdvice是Spring框架中用于处理HTTP请求体的一个接口,它允许我们在控制器处理请求之前对请求体进行一些自定义操作。

这个接口通常用于对请求体进行校验、转换或者日志记录等操作。

RequestBodyAdvice接口提供了下面几个方法:

a. supports: 这个方法用于判断当前的RequestBodyAdvice是否适用于给定的控制器方法参数。

b. beforeBodyRead: 这个方法在请求体被读取并反序列化为对象之前调用,可以在这里对请求体进行预处理。

c. afterBodyRead: 这个方法在请求体被读取并反序列化为对象之后调用,可以在这里对反序列化后的对象进行后处理。

d.handleEmptyBody: 这个方法在请求没有请求体时调用,可以在这里提供默认值或者进行其他处理。

我们来重写上面的方法吧,只要是重写beforeBodyRead来实现。

二、beforeBodyRead

/**
 * Invoked second before the request body is read and converted.
 *
 * @param inputMessage  the request
 * @param parameter     the target method parameter
 * @param targetType    the target type, not necessarily the same as the method
 *                      parameter type, e.g. for {@code HttpEntity<String>}.
 * @param converterType the converter used to deserialize the body
 * @return the input request or a new instance, never {@code null}
 */
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
    try {
        return new RequestHttpInputMessage(inputMessage, parameter);
    } catch (Exception e) {
        return inputMessage;
    }
}

RequestHttpInputMessage是一个继承HttpInputMessage的自定义类。

三、HttpInputMessage获取API接口头和请求体

HttpInputMessage 它代表了一个 HTTP 输入消息,通常用于读取 HTTP 请求的正文,这个接口提供了对 HTTP 请求头和请求体的访问。

HttpInputMessage 接口定义了以下两个方法:

  1. getHeaders(): 返回一个不可变的 MultiValueMap<String, String>,包含了 HTTP 消息头的键值对。这些消息头可以包含如内容类型、内容长度、缓存控制等信息。

  2. getBody(): 返回一个 InputStream,通过这个流可以读取 HTTP 消息的正文。这通常用于读取客户端发送的数据,如 JSON 或 XML 格式的数据。

    注意:getBody是一次性的方法,当你使用了一次获取了InputStream之后,再使用此方法,是无法再次获取到的。为了规避此问题,我们应该使用如下代码块进行获取。

final ByteArrayInputStream bais = new ByteArrayInputStream(readBytes(body));

privatebyte[] readBytes(InputStream in) throws IOException {
    int buffSize = 1024;
    try (BufferedInputStream bis = new BufferedInputStream(in); ByteArrayOutputStream out = new ByteArrayOutputStream(buffSize)) {
        byte[] temp = new byte[buffSize];
        int size;
        while ((size = bis.read(temp)) != -1) {
            out.write(temp, 0, size);
        }
        return out.toByteArray();
    }
}

四、实现RequestHttpInputMessage

我们来实现一下这个RequestHttpInputMessage,主要在构造函数内进行解密即可。

public RequestHttpInputMessage(HttpInputMessage inputMessage, MethodParameter parameter) throws Exception {
      this.headers = inputMessage.getHeaders();
      String encryptStr = easeString(IOUtils.toString(inputMessage.getBody(), StandardCharsets.UTF_8));
      // 解密
      String decrypt = AesEncryptUtils.decrypt(encryptStr);
      String replace = decrypt;
      log.info("RequestHttpInputMessage:{}", replace);
      // 特殊处理
      if (decrypt.contains("certImages")) {
          replace = decrypt.replace("\\", "");
      }
      // 解密后的请求块
      this.body = IOUtils.toInputStream(replace, StandardCharsets.UTF_8);
  }

AesEncryptUtils.decrypt属于请求块的解密方法。假如有特殊的请求,我们可以进行方法变通。最后更改请求块,然后将解密后的请求块发送给Controller了。

另外需要我自己的加密类,可以留言联系我获取,谢谢~

猜你喜欢

转载自blog.csdn.net/t610654893/article/details/138966511