Springsecurity的版本是4.3.x,源碼可以在Github上下載。
1、ExceptionTranslationFilter的doFilter
ExceptionTranslationFilter是個異常過濾器,用來處理在認證授權過程中拋出的異常,ExceptionTranslationFilter後面的過濾器是FilterSecurityInterceptor。先上一張圖,如下圖1所示:
圖1
- 紅框1中的,是調用Filter鏈中的後續Filter。
- 如果圖1中的操作拋出異常,就會來到紅框2處,判斷拋出的異常是否是AuthenticationException。
- 如果拋出的異常不是AuthenticationException,即紅框2的結果爲null,那麼就到紅框3處,判斷是否是AccessDeniedException。
- 如果拋出的異常是AuthenticationException或者時AccessDeniedException,那麼執行紅框4處的代碼。
2、ExceptionTranslationFilter的handleSpringSecurityException方法
下面來看handleSpringSecurityException的方法體,如下List-1所示
List-1
private void handleSpringSecurityException(HttpServletRequest request,
HttpServletResponse response, FilterChain chain, RuntimeException exception)
throws IOException, ServletException {
if (exception instanceof AuthenticationException) {
logger.debug(
"Authentication exception occurred; redirecting to authentication entry point",
exception);
sendStartAuthentication(request, response, chain,
(AuthenticationException) exception);
}
else if (exception instanceof AccessDeniedException) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authenticationTrustResolver.isAnonymous(authentication) || authenticationTrustResolver.isRememberMe(authentication)) {
logger.debug(
"Access is denied (user is " + (authenticationTrustResolver.isAnonymous(authentication) ? "anonymous" : "not fully authenticated") + "); redirecting to authentication entry point",
exception);
sendStartAuthentication(
request,
response,
chain,
new InsufficientAuthenticationException(
messages.getMessage(
"ExceptionTranslationFilter.insufficientAuthentication",
"Full authentication is required to access this resource")));
}
else {
logger.debug(
"Access is denied (user is not anonymous); delegating to AccessDeniedHandler",
exception);
accessDeniedHandler.handle(request, response,
(AccessDeniedException) exception);
}
}
}
- 如果拋出的異常是AuthenticationException,則執行方法sendStartAuthentication
- 如果拋出的異常是AccessDeniedException,且從SecurityContextHolder.getContext().getAuthentication()得到的是AnonymousAuthenticationToken或者RememberMeAuthenticationToken,那麼執行sendStartAuthentication
- 如果上面的第二點不滿足,則執行accessDeniedHandler的handle方法
3、ExceptionTranslationFilter的sendStartAuthentication方法
如下List-2所示,會調用authenticationEntryPoint的commence方法。
List-2
protected void sendStartAuthentication(HttpServletRequest request,
HttpServletResponse response, FilterChain chain,
AuthenticationException reason) throws ServletException, IOException {
// SEC-112: Clear the SecurityContextHolder's Authentication, as the
// existing Authentication is no longer considered valid
SecurityContextHolder.getContext().setAuthentication(null);
requestCache.saveRequest(request, response);
logger.debug("Calling Authentication entry point.");
authenticationEntryPoint.commence(request, response, reason);
}
思考:
- 我們有時候會在xml配置中配置accessDeniedHandler,是在這裏用到嗎?
- List-2中使用到的authenticationEntryPoint,是什麼?