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,是什么?