SpringSecurity异常处理

// 用户名,密码认证
// 异常处理:通过过滤器自身捕获异常,将结果放到响应体中,直接返回。
class UsernamePasswordAuthenticationFilter {

    //实现类 AntPathRequestMatcher 属性pattern=‘/login’ ,httpMethod=POST
    private RequestMatcher requiresAuthenticationRequestMatcher;
    
    // 认证管理器对象
    private AuthenticationManager authenticationManager;
    
    // 接口SessionAuthenticationStrategy.onAuthentication(...)
    //  实现类NullAuthenticatedSessionStrategy 不做任何处理
    //  实现类CompositeSessionAuthenticationStrategy多个策略组合执行
    private SessionAuthenticationStrategy sessionStrategy;
    
    // 接口AuthenticationSuccessHandler.onAuthenticationSuccess(...)
    // 实现类SimpleUrlAuthenticationSuccessHandler
    // 实现类SavedRequestAwareAuthenticationSuccessHandler
    // 实现类ForwardAuthenticationSuccessHandler
    private AuthenticationSuccessHandler successHandler;

    // 接口AuthenticationFailureHandler.onAuthenticationFailure(...)
    // ForwardAuthenticationFailureHandler
    // SimpleUrlAuthenticationFailureHandler
    // ExceptionMappingAuthenticationFailureHandler
    // DelegatingAuthenticationFailureHandler多个失败认证处理组合执行
    private AuthenticationFailureHandler failureHandler;

    void doFilter(ServletRequest req, ServletResponse res, FilterChain chain){
        // 放行请求路径不为/login && POST的请求
        if (!this.requiresAuthentication(request, response)) {
                  chain.doFilter(request, response);
        } else {
            try {
                // 调用IOC中的ProviderManager对象进行认证处理
                authResult = this.attemptAuthentication(request, response)->{
                    return this.getAuthenticationManager().authenticate(authRequest);
                };
                //主要负责处理认证成功的时候session需要执行的逻辑
                this.sessionStrategy.onAuthentication(authResult, request, response); 
            // 捕获AuthenticationException异常
            } catch(AuthenticationException var9){
                this.unsuccessfulAuthentication(request, response, var8)->{
                    //清除authResult
                    SecurityContextHolder.clearContext();
                    
                    // failureHandler为SimpleUrlAuthenticationFailureHandler
                    //  其属性defaultFailureUrl=‘/login/?error’
                    //  其属性RedirectStrategy redirectStrategy = new 
                    //                             DefaultRedirectStrategy();
                    this.failureHandler.onAuthenticationFailure(...)->{
                        //this.defaultFailureUrl != null
                        // 重定向到/login?error路径,进行登陆
                        this.redirectStrategy.sendRedirect(request, response, 
                                                 this.defaultFailureUrl);
                    }
                }
                // 过滤链调用结束
                return;
            }
            // 成功之后的认证处理
            this.successfulAuthentication(request, response, chain, authResult); 
        } 
       
    }
}
// 异常处理:通过过滤器自身捕获异常,接口AuthenticationEntryPoint.commence()
//  处理异常后,直接返回。
class BasicAuthenticationFilter {
    
    // 接口AuthenticationEntryPoint.commence(...)
    // 实现类BasicAuthenticationEntryPoint
    // 实现类DelegatingAuthenticationEntryPoint
    // 实现类DigestAuthenticationEntryPoint
    // 实现类HttpStatusEntryPoint
    private AuthenticationEntryPoint authenticationEntryPoint;

    //接口AuthenticationDetailsSource.buildDetails(...)
    // 实现类WebAuthenticationDetailsSource
    //     buildDetails(HttpServletRequest context)->{new 
    //           WebAuthenticationDetails(context);}
    // 类WebAuthenticationDetails对象的属性String remoteAddress,String sessionId;
    private AuthenticationDetailsSource<HttpServletRequest, ?> 
                                  authenticationDetailsSource;

    void doFilterInternal(...){
         String header = request.getHeader("Authorization");
         
         try {
             String[] tokens = this.extractAndDecodeHeader(header, request);
             UsernamePasswordAuthenticationToken authRequest = new 
                         UsernamePasswordAuthenticationToken(username, tokens[1]);
         
             //接口Authentication.getPrincipal()/isAuthenticated()/getPrincipal() 
                        setAuthenticated(boolean var1)
             // 实现类UsernamePasswordAuthenticationToken
             //     其中一个属性private Object details;
             //  从请求中获取remoteAddress和sessionId构成对象,
             //  设置到authRequest.details中
             authRequest.setDetails(this.authenticationDetailsSource.buil
                 dDetails(request));
         
             // 调用认证管理器认证
             Authentication authResult = 
                                this.authenticationManager.authenticate(authRequest);
         
             // SecurityContextHolder类
             //    属性private static SecurityContextHolderStrategy strategy;
             // 接口SecurityContextHolderStrategy.clearContext()/setContext()
             // 实现类ThreadLocalSecurityContextHolderStrategy
             //    属性private static final ThreadLocal<SecurityContext> contextHolder;
             // 实现类 GlobalSecurityContextHolderStrategy
             //    属性private static SecurityContext contextHolder;
             // 实现类 InheritableThreadLocalSecurityContextHolderStrategy
             //    属性private static final ThreadLocal<SecurityContext> contextHolder;

             // 接口SecurityContext.getAuthentication()|setAuthentication(...)
             // 实现类SecurityContextImpl
             //    属性private Authentication authentication 
             //                      该属性储存...AuthenticationToken对象
             SecurityContextHolder.getContext().setAuthentication(authResult);   
         
             // BasicAuthenticationFilter。onSuccessfulAuthentication(..) doNothing
             this.onSuccessfulAuthentication(request, response, authResult);
        } catch (AuthenticationException var10){
             // DelegatingAuthenticationEntryPoint
             //   属性LinkedHashMap<RequestMatcher, AuthenticationEntryPoint> 
             //        entryPoints;
             //        key=RequestHeaderRequestMatcher类
             //                   属性expectedHeaderName=X-Requested-With
             //                   属性expectedHeaderValue=XMLHttpRequest
             //        value=HttpStatusEntryPoint类
             //                   属性HttpStatus枚举 UNAUTHORIZED(401, "Unauthorized")
             //   属性private AuthenticationEntryPoint defaultEntryPoint;
             //        realmName = "Realm"
             this.authenticationEntryPoint.commence(request, response, var10)->{
                 BasicAuthenticationEntryPoint.commence()->{
                     response.addHeader("WWW-Authenticate", "Basic realm=\"" + 
                              this.realmName + "\"");
                     response.sendError(HttpStatus.UNAUTHORIZED.value(), 
                              HttpStatus.UNAUTHORIZED.getReasonPhrase());
                 }
             };
             return;
        }
    }
}


//异常处理:捕获FilterSecurityInterceptor中抛出的异常
// 如果异常为AuthenticationException及子类,调用接口AuthenticationEntryPoint.commence
//          ()方法的子类实现处理
// 如果异常为AccessDeniedException及子类,调用接口AccessDeniedHandler.handle
//          ()方法的子类实现处理
public class ExceptionTranslationFilter {
    // 接口AccessDeniedHandler.handle() 处理AccessDeniedException异常
    // 实现类DelegatingAccessDeniedHandler
    // 实现类AccessDeniedHandlerImpl
    // 实现类InvalidSessionAccessDeniedHandler
    private AccessDeniedHandler accessDeniedHandler;
    
    // 与BasicAuthenticationFilter类中的authenticationEntryPoint相同
    private AuthenticationEntryPoint authenticationEntryPoint;
    
    //接口AuthenticationTrustResolver.isAnonymous()|isRememberMe()
    // 实现类AuthenticationTrustResolverImpl
    //   属性anonymousClass = AnonymousAuthenticationToken.class;
    //   属性rememberMeClass = RememberMeAuthenticationToken;
    private AuthenticationTrustResolver authenticationTrustResolver;

    public void doFilter(...){
        try {
            chain.doFilter(request, response)—>{
                // FilterInvocation类
                // 属性chain,请求,响应
                FilterInvocation fi = new FilterInvocation(request, response, chain);
                this.invoke(fi)->{
                     //过滤器仅执行1次的逻辑
                     
                     InterceptorStatusToken token = super.beforeInvocation(fi)—>{
                          // 根据url获取Collection<ConfigAttribute>
                          Collection<ConfigAttribute> attributes = 
                             this.obtainSecurityMetadataSource().getAttributes(object);
                          //attributes不为null,则
                          //判断SecurityContextHolder中的authentication.isAuthenticated()
                          // 为ture,则返回,为false,则调用 
                          //  this.authenticationManager.authenticate(authentication)
                          //  将结果返回
                          Authentication authenticated = this.authenticateIfRequired();
    
                          try {
                              //AffirmativeBased类
                              //  属性List<AccessDecisionVoter<T> decisionVoters;
                              //         值为decisionVoters[0]=WebExpressionVoter
                              //WebExpressionVoter类
                              //  属性SecurityExpressionHandler<FilterInvocation> 
                              //                               expressionHandler;
                              //          值DefaultWebSecurityExpressionHandler
                              this.accessDecisionManager.decide(authenticated, object, 
                                         attributes);
                          } catch (AccessDeniedException var7) {
                              //发布AuthorizationFailureEvent事件
                              this.publishEvent(new AuthorizationFailureEvent(object,     
                                   attributes, authenticated, var7));
                              // 抛出,由上层捕获
                              throw var7;
                          }

                          if (this.publishAuthorizationSuccess) {
                              //发布AuthorizedEvent事件
                              this.publishEvent(new AuthorizedEvent(object, attributes,             
                                               authenticated));
                          }
                     };
                };
            };
            this.logger.debug("Chain processed normally");
        //捕获当前过滤器和接下来的过滤器所抛出的异常
        } catch (IOException var9) {
            throw var9;
        } catch (Exception var10) {
            // 获取Cause的异常
            Throwable[] causeChain = this.throwableAnalyzer.determineCauseChain(var10);
            // 如果为AuthenticationException的子类,则
            RuntimeException ase = (AuthenticationException)this.throwableAnalyzer       
                                        .getFirstThrowableOfType(...);
            if (ase == null) {
                //如果为AccessDeniedException异常及子类,则
                ase = (AccessDeniedException)this.thr
                      owableAnalyzer.getFirstThrowableOfType(...);
            }

            if (ase == null) {
                // 其他情况
                if (var10 instanceof ServletException) {
                    throw (ServletException)var10;
                }

                if (var10 instanceof RuntimeException) {
                    throw (RuntimeException)var10;
                }

                throw new RuntimeException(var10);
            }

            if (response.isCommitted()) {
                throw new ServletException("Unable to handle the Spring Security Exception because the response is already committed.", var10);
            }
            
            // 处理异常
            this.handleSpringSecurityException(request, response, chain, 
                      (RuntimeException)ase)-{
                // 异常为AuthenticationException及子类
                if (exception instanceof AuthenticationException) {
                    // 清除SecurityContext
                    SecurityContextHolder.getContext().setAuth
                                    entication((Authentication)null);
                    this.requestCache.saveRequest(request, response);    
                    // 使用AuthenticationEntryPoint的接口实现类处理异常
                    this.authenticationEntryPoint.commence(request, response, reason);
                }else if (exception instanceof AccessDeniedException) {
                    //如果authentication对象不是AnonymousAuthenticationToken或者 
                    //    RememberMeAuthenticationToken,则
                    //使用AccessDeniedHandler接口的AccessDeniedHandlerImpl实现类
                    this.accessDeniedHandler.handle(...)—>{
                        //如果有错误页面,设置响应403,重定向到错误页面
                        //否则,设置响应403
                    };

                    //否则,传入InsufficientAuthenticationException
                    this.sendStartAuthentication(...);
                }
            };
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Security提供了许多方式来处理身份验证和授权的异常。下面是一些常见的异常处理方式: 1. 使用Spring的全局异常处理器:可以通过在应用程序中定义一个`@ControllerAdvice`类,并使用`@ExceptionHandler`注解来处理Spring Security异常。在异常处理方法中,可以根据不同的异常类型进行相应的处理,例如返回自定义的错误页面或者JSON响应。 ```java @ControllerAdvice public class SecurityExceptionHandler { @ExceptionHandler(AuthenticationException.class) public ResponseEntity<String> handleAuthenticationException(AuthenticationException ex) { // 处理身份验证异常 return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(ex.getMessage()); } @ExceptionHandler(AccessDeniedException.class) public ResponseEntity<String> handleAccessDeniedException(AccessDeniedException ex) { // 处理访问拒绝异常 return ResponseEntity.status(HttpStatus.FORBIDDEN).body(ex.getMessage()); } // 其他异常处理方法... } ``` 2. 自定义AccessDeniedHandler:可以实现`AccessDeniedHandler`接口来处理访问拒绝异常。可以在`handle()`方法中自定义处理逻辑,例如返回自定义的错误页面或者JSON响应。 ```java public class CustomAccessDeniedHandler implements AccessDeniedHandler { @Override public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException ex) throws IOException, ServletException { // 处理访问拒绝异常 response.sendError(HttpServletResponse.SC_FORBIDDEN, ex.getMessage()); } } ``` 然后,在Spring Security配置中指定自定义的`AccessDeniedHandler`: ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { // ... @Override protected void configure(HttpSecurity http) throws Exception { http // ... .exceptionHandling() .accessDeniedHandler(new CustomAccessDeniedHandler()) // ... } // ... } ``` 这些只是处理Spring Security异常的两种常见方式,你可以根据实际需求选择适合的方式进行异常处理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值