SpringBoot过滤器修改请求体的内容

1,675 阅读1分钟

前言

业务上有个需求,前端调用后端接口时传的是加密数据,所以后端无法正常接收数据。需要写一个过滤器,在过滤器那里拦截请求并解密数据。

问题复现

public Result create(@RequestBody String event) {
    // do something
    return Result.success();
}

由于前端传的是加密值,并不是Json数据,@RequestBody解析Json会抛出异常

解决方法

编写过滤器,拦截需要解密数据的请求。ServletRequest没有提供修改请求参数、请求体的方法,所以我们只能重写一个HttpServletRequestWrapper类,替换ServletRequest,拦截获取请求参数、请求体的方法,在方法内部进行解密。

启动类注解

@SpringBootApplication
// 加上@ServletComponentScan注解,自动扫描注册过滤器,否则@WebFilter注解不生效
@ServletComponentScan
public class RestApplication {
    public static void main(String[] args) {
        SpringApplication springApplication = new SpringApplication(RestApplication.class);
        springApplication.run(args);
    }
}

过滤器代码

@WebFilter(urlPatterns = "/accept/*",filterName = "KwaiMsgFilter")
public class KwaiMsgFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // 用自己实现HttpServletRequestWrapper类,替换servletRequest
        filterChain.doFilter(new KwaiMsgHttpServletRequestWrapper((HttpServletRequest) servletRequest), servletResponse);
    }
}

KwaiMsgHttpServletRequestWrapper代码

public class KwaiMsgHttpServletRequestWrapper extends HttpServletRequestWrapper {
    public KwaiMsgHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
    }

    /**
     * 修改getInputStream方法
     * @return
     */
    @SneakyThrows
    @Override
    public ServletInputStream getInputStream() {
        // 获取请求体数据
        BufferedReader reader=super.getReader();
        String str, wholeStr = "";
        while((str = reader.readLine()) != null){
            wholeStr += str;
        }
        // 解密
        String msg=PlatformEventSecurityUtil.decode(wholeStr, "秘钥");
        InputStream inputStream=new ByteArrayInputStream(msg.getBytes(StandardCharsets.UTF_8));
        // 返回
        return new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return false;
            }
            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {

            }
            @Override
            public int read() throws IOException {
                return inputStream.read();
            }
        };
    }
}

总结

这样子Controller层就可以收到解密后的数据了,我这里只修改了getInputStream()方法,getParameter(String)等方法,可根据业务需求自己修改。