今天做專案的時候,發現每次攔截器日誌都會打兩遍,很納悶,懷疑是Filter被執行了兩遍。結果debug之後發現還真是!記錄一下這個神奇的BUG!
問題描述
專案中使用的是Spring-security作為許可權框架,然後做了一個JwtAuthenticationTokenFilter
作為攔截器攔截請求,校驗Token,但是每次請求都會打兩遍日誌。下面是精簡的原始碼:
自定義的Filter類
@Slf4j
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(
HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) throws ServletException, IOException {
//...省略
//打出兩遍日誌的地方
log.info("User:{} request path:{}, method:{}, param:{}", username, request.getServletPath(),
request.getMethod(), request.getParameterMap() == null ? null : OBJECT_MAPPER.writeValueAsString(request.getParameterMap()));
//...省略
chain.doFilter(request, response);
}
}
複製程式碼
WebSecurityConfig配置類
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
//...省略
@Bean
public JwtAuthenticationTokenFilter authenticationTokenFilterBean() throws Exception {
return new JwtAuthenticationTokenFilter();
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
//...省略
//把JwtAuthenticationTokenFilter加入到RememberMeAuthenticationFilter之前
httpSecurity.addFilterBefore(authenticationTokenFilterBean(), RememberMeAuthenticationFilter.class);
}
//...省略
}
複製程式碼
請求日誌如下:
問題解決
把自定義FilterJwtAuthenticationTokenFilter
的@Component
取消掉就可以了,不讓它被Spring容器管理。
原因
在spring容器託管的OncePerRequestFilter的bean,都會自動加入到servlet的filter chain,而上面的定義,還額外把filter加入到了spring security的 ememberMeAuthenticationFilter之前。而spring security也是一系列的filter,在mvc的filter之前執行。因此在鑑權通過的情況下,就會先後各執行一次。