1. 程式人生 > 其它 >Springboot關於在攔截器中列印相關日誌和鑑權的若干點

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();
    }
}