Springboot关于在拦截器中打印相关日志和鉴权的若干点

需求:在filter中进行请求日志的打印(有时候是因为数据的序列化出错),做简单鉴权

java中springboot,request body InputStream流的读取只能读取一次,读完就没,如果在filter中直接读取了,到controller中数据就拿不到了。所以springboot提供了 ContentCachingRequestWrapper 这个类来进行包裹。

先看这个类的名称可以踩个大概就是做request的缓存用的。

// 代码如下,基本原理是将原始的request初始化wrappedRequest,然后用这个变量贯穿整个请求过程,
// 值得注意的是wrappedRequest这个工作原理是read()函数被调用的过程中缓存,也就是说这个原理是springboot/mvc在controller进行body数据读取的时候,读出来了再把数据copy一份到cache中,所以wrappedRequest就能反复读取数据。
// 在下列代码中 执行的顺序 是 doFilter() 调用 read()函数,wrappedRequest中的数据就被copy完毕,所以recordReq() 和 recordResp() 函数参数就能访问到请求数据,如果不使用wrappedRequest,那么数据读取完后request中数据就空了。
// 这边值得注意的是在权限验证失败时候手动调用了wrappedRequest.getReader().read(),意在将数据刷到wrappedRequest中。
@Component
@WebFilter(filterName = "authenticationFilter", urlPatterns = "/*")
@Order(-9999)
@Slf4j
public class AuthenticationFilter extends GenericFilterBean {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
            throws IOException, ServletException {
        ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper((HttpServletRequest) servletRequest);
        ContentCachingResponseWrapper wrappedResponse = new ContentCachingResponseWrapper((HttpServletResponse) servletResponse);
        // 授权认证
        Optional<String> origin = authentication(wrappedRequest);
        long start = TimeUtils.getLongTimeMillis();
        if (origin.isEmpty()) {
            // 手动读取,将结果刷新到wrappedRequest中
            wrappedRequest.getReader().read();
            // 为携带Token
            wrappedResponse.setStatus(HttpServletResponse.SC_OK);
            String str = GsonUtils.toJson(BaseResponse.fail(ResultCode.AUTHORIZE_FAILED));
            //设置 HttpServletResponse使用utf-8编码
            wrappedResponse.setCharacterEncoding("utf-8");
            //设置响应头的编码
            wrappedResponse.setHeader("Content-Type", "application/json;charset=utf-8");
            wrappedResponse.getWriter().write(str);
        } else {
            chain.doFilter(wrappedRequest, wrappedResponse);
        }
        long end = TimeUtils.getLongTimeMillis();
        // 记录请求信息
        recordReq(wrappedRequest, origin);
        // 记录response信息
        recordResp(wrappedRequest, wrappedResponse, end - start);
        // 这一步很重要,把缓存的响应内容,输出到客户端
        wrappedResponse.copyBodyToResponse();
    }
}
posted @ 2022-05-18 18:13  多枝的树  阅读(678)  评论(0)    收藏  举报