zoukankan      html  css  js  c++  java
  • Springsecurity源码Filter之ExceptionTranslationFilter(十八)

    统一的异常处理过滤器,我们可以处理统一的身份认证或者授权的异常 比如未登录访问登录页面 需要认证权限的地方

    通过HttpSecurity  可以指定 

    通过org.springframework.security.config.annotation.web.configurers.ExceptionHandlingConfigurer

    private void applyDefaultConfiguration(HttpSecurity http) throws Exception {
            //http本质也是build 这里都是配置默认的config configure add CsrfConfigurer
            http.csrf();
            //默认增加一个WebAsyncManagerIntegrationFilter
            http.addFilter(new WebAsyncManagerIntegrationFilter());
            //configures add ExceptionHandlingConfigurer
            http.exceptionHandling();
            //configures add HeadersConfigurer
            http.headers();
            //configures add SessionManagementConfigurer
            http.sessionManagement();
            //configure add SecurityContextConfigurer
            http.securityContext();
            //configure add RequestCacheConfigurer
            http.requestCache();
            ///configure add AnonymousConfigurer
            http.anonymous();
            ///configure add ServletApiConfigurer
            http.servletApi();
            //configure DefaultLoginPageConfigurer
            http.apply(new DefaultLoginPageConfigurer<>());
            //configure LogoutConfigurer
            http.logout();
        }

    org.springframework.security.config.annotation.web.configurers.ExceptionHandlingConfigurer#configure

     @Override
        public void configure(H http) {
            //身份验证入口点(驱动应用开始进行身份验证),用于启动身份验证方案(默认:Http403ForbiddenEntryPoint)
            AuthenticationEntryPoint entryPoint = getAuthenticationEntryPoint(http);
            ExceptionTranslationFilter exceptionTranslationFilter = new ExceptionTranslationFilter(entryPoint,
                    getRequestCache(http));
            //获得处理异常的handle
            AccessDeniedHandler deniedHandler = getAccessDeniedHandler(http);
            exceptionTranslationFilter.setAccessDeniedHandler(deniedHandler);
            //autowired注入
            exceptionTranslationFilter = postProcess(exceptionTranslationFilter);
            //加入httpConfig
            http.addFilter(exceptionTranslationFilter);
        }

    org.springframework.security.web.access.ExceptionTranslationFilter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)

     private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
                throws IOException, ServletException {
            //tryCath捕获异常
            try {
                chain.doFilter(request, response);
            }
            catch (IOException ex) {
                throw ex;
            }
            catch (Exception ex) {
    
                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);
                }
                //<1>处理异常
                handleSpringSecurityException(request, response, chain, securityException);
            }
        }

    <1>

    org.springframework.security.web.access.ExceptionTranslationFilter#handleSpringSecurityException

     private void handleSpringSecurityException(HttpServletRequest request, HttpServletResponse response,
                                                   FilterChain chain, RuntimeException exception) throws IOException, ServletException {
            //授权类异常
            if (exception instanceof AuthenticationException) {
                //<2>
                handleAuthenticationException(request, response, chain, (AuthenticationException) exception);
            }
            //身份认证异常
            else if (exception instanceof AccessDeniedException) {
               // <4>
                handleAccessDeniedException(request, response, chain, (AccessDeniedException) exception);
            }
        }

    <2>

     private void handleAuthenticationException(HttpServletRequest request, HttpServletResponse response,
                                                   FilterChain chain, AuthenticationException exception) throws ServletException, IOException {
            //<3>
            sendStartAuthentication(request, response, chain, exception);
        }

    <3>

     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);
            //保存当前Request的请求信息,例如:header、cookie、path等,以便在用户进行身份验证后可以检索和重用该请求
            requestCache.saveRequest(request, response);
            logger.debug("Calling Authentication entry point.");
            //开始启动验证(例如通过重定向到登录界面)
            authenticationEntryPoint.commence(request, response, reason);
        }

    <4>

     private void handleAccessDeniedException(HttpServletRequest request, HttpServletResponse response,
                                                 FilterChain chain, AccessDeniedException exception) throws ServletException, IOException {
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            /**
             * 判断是是否是记住登录或者是未登录authenticationTrustResolver
             * authenticationTrustResolver主要是判断authentication是否是AnonymousAuthenticationToken
             * 或者RememberMeAuthenticationToken 类型
             */
            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);
                }
                //交由accessDeniedHandler 处理
                this.accessDeniedHandler.handle(request, response, exception);
            }
        }
    
        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);
            this.requestCache.saveRequest(request, response);
            //最终交给authenticationEntryPoint处理
            this.authenticationEntryPoint.commence(request, response, reason);
        }
  • 相关阅读:
    UVA 1025 A Spy in the Metro DP水题
    ZOJ 3814 Sawtooth Puzzle BFS
    ZOJ 3816 Generalized Palindromic Number
    UVA 10859 Placing Lampposts 树形DP
    UVA 11825 Hackers' Crackdown 状压DP
    POJ 2887 Big String 线段树 离线处理
    POJ 1635 Subway tree systems Hash法判断有根树是否同构
    BZOJ 3110 k大数查询 & 树套树
    sdoi 2009 & 状态压缩
    来自于2016.2.24的flag
  • 原文地址:https://www.cnblogs.com/LQBlog/p/15546062.html
Copyright © 2011-2022 走看看