public final class ExceptionHandlingConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<ExceptionHandlingConfigurer<H>, H> {
private AuthenticationEntryPoint authenticationEntryPoint;
private AccessDeniedHandler accessDeniedHandler;
private LinkedHashMap<RequestMatcher, AuthenticationEntryPoint> defaultEntryPointMappings = new LinkedHashMap<>();
private LinkedHashMap<RequestMatcher, AccessDeniedHandler> defaultDeniedHandlerMappings = new LinkedHashMap<>();
}
public void configure(H http) {
//获得身份认证入口点
AuthenticationEntryPoint entryPoint = getAuthenticationEntryPoint(http);
//创建处理异常的过滤器,还传入了请求缓存器
ExceptionTranslationFilter exceptionTranslationFilter = new ExceptionTranslationFilter(entryPoint,
getRequestCache(http));
//获得访问被拒绝处理器
AccessDeniedHandler deniedHandler = getAccessDeniedHandler(http);
exceptionTranslationFilter.setAccessDeniedHandler(deniedHandler);
//进行objectPostProcessor处理
exceptionTranslationFilter = postProcess(exceptionTranslationFilter);
//添加过滤器到httpSecurity中
http.addFilter(exceptionTranslationFilter);
}
private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
try {
chain.doFilter(request, response);
}
catch (IOException ex) {
throw ex;
}
catch (Exception ex) {
//尝试从堆栈跟踪中提取SpringSecurityException,不懂
Throwable[] causeChain = this.throwableAnalyzer.determineCauseChain(ex);
//拿到认证异常
RuntimeException securityException = (AuthenticationException) this.throwableAnalyzer
.getFirstThrowableOfType(AuthenticationException.class, causeChain);
//不是一个认证异常
if (securityException == null) {
securityException = (AccessDeniedException) this.throwableAnalyzer
.getFirstThrowableOfType(AccessDeniedException.class, causeChain);
}
//既不是认证异常也不是访问被拒绝异常,那就继续抛
if (securityException == null) {
rethrow(ex);
}
if (response.isCommitted()) {
throw new ServletException("Unable to handle the Spring Security Exception "
+ "because the response is already committed.", ex);
}
//处理SpringSecurity异常
handleSpringSecurityException(request, response, chain, securityException);
}
}
private void handleSpringSecurityException(HttpServletRequest request, HttpServletResponse response,
FilterChain chain, RuntimeException exception) throws IOException, ServletException {
//是一个认证异常
if (exception instanceof AuthenticationException) {
handleAuthenticationException(request, response, chain, (AuthenticationException) exception);
}
//是一个访问被拒绝异常
else if (exception instanceof AccessDeniedException) {
handleAccessDeniedException(request, response, chain, (AccessDeniedException) exception);
}
}
private void handleAuthenticationException(HttpServletRequest request, HttpServletResponse response,
FilterChain chain, AuthenticationException exception) throws ServletException, IOException {
this.logger.trace("Sending to authentication entry point since authentication failed", exception);
sendStartAuthentication(request, response, chain, exception);
}
/**
* 处理认证异常
*/
protected void sendStartAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
AuthenticationException reason) throws ServletException, IOException {
//清除存储在线程级别的上下文策略的认证信息,HttpSession级别的会在SecurityContextPersistenceFilter的finally代码块中被更新
//因为现有的认证不再被认为有效
SecurityContext context = SecurityContextHolder.createEmptyContext();
SecurityContextHolder.setContext(context);
//将当前的请求放入请求缓存器
//这样当重新登录后,还能将请求包装为这一次请求
this.requestCache.saveRequest(request, response);
//执行认证异常处理器
this.authenticationEntryPoint.commence(request, response, reason);
}
private void handleAccessDeniedException(HttpServletRequest request, HttpServletResponse response,
FilterChain chain, AccessDeniedException exception) throws ServletException, IOException {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
boolean isAnonymous = this.authenticationTrustResolver.isAnonymous(authentication);
//当是匿名用户和记住我用户
if (isAnonymous || this.authenticationTrustResolver.isRememberMe(authentication)) {
if (logger.isTraceEnabled()) {
logger.trace(LogMessage.format("Sending %s to authentication entry point since access is denied",
authentication), exception);
}
//还是当成一个认证异常处理
//表示需要完整登录(用用户名和密码登录)
sendStartAuthentication(request, response, chain,
new InsufficientAuthenticationException(
this.messages.getMessage("ExceptionTranslationFilter.insufficientAuthentication",
"Full authentication is required to access this resource")));
}
else {
if (logger.isTraceEnabled()) {
logger.trace(
LogMessage.format("Sending %s to access denied handler since access is denied", authentication),
exception);
}
//调用访问被拒绝处理器,进行处理
this.accessDeniedHandler.handle(request, response, exception);
}
}
因篇幅问题不能全部显示,请点此查看更多更全内容