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);
        }
  • 相关阅读:
    deepin 安装微信与QQ
    安装git
    在ubuntu上安装最新稳定版本的node及npm
    如何恢复Initial commit之前的源文件
    git使用之错误分析及解决(持续更新)
    【翻译】在Ext JS 5应用程序中如何使用路由
    【翻译】Sencha Ext JS 5发布
    【翻译】Ext JS 4——Ajax和Rest代理处理服务器端一场和消息的方法
    【翻译】Ext JS——高效的编码风格指南
    【翻译】在Ext JS 5种使用ViewControllers
  • 原文地址:https://www.cnblogs.com/LQBlog/p/15546062.html
Copyright © 2011-2022 走看看