`
Dead_knight
  • 浏览: 1201016 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
博客专栏
752c8642-b795-3fe6-946e-a4e845bffdec
Spring Securi...
浏览量:240209
33caa84e-18a6-3036-a82b-6e2106a4de63
clojure专题
浏览量:48920
E17ca077-44df-3816-a3fe-471c43f6e1e5
WebLogic11g
浏览量:236876
社区版块
存档分类
最新评论

Spring Security3源码分析-ExceptionTranslationFilter分析

阅读更多
ExceptionTranslationFilter过滤器对应的类路径为
org.springframework.security.web.access.ExceptionTranslationFilter
从类名就看出这个过滤器用于异常翻译的。但是从这个过滤器在filterchain中的位置来看,它仅仅处于倒数第三的位置(这个filter后面分为是FilterSecurityInterceptor、SwitchUserFilter),所以ExceptionTranslationFilter只能捕获到后面两个过滤器所抛出的异常。
这里需要强调一下,spring security中的异常类基本上都继承RuntimeException。

接着看ExceptionTranslationFilter执行过程
    //doFilter拦截到请求时,不做处理。仅仅处理后面filter所抛出的异常
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        try {
            chain.doFilter(request, response);
        }
        catch (IOException ex) {
            throw ex;
        }
        catch (Exception ex) {
            //这里主要是从异常堆栈中提取SpringSecurityException
            Throwable[] causeChain = throwableAnalyzer.determineCauseChain(ex);
            RuntimeException ase = (AuthenticationException)
                    throwableAnalyzer.getFirstThrowableOfType(AuthenticationException.class, causeChain);

            if (ase == null) {
                ase = (AccessDeniedException)throwableAnalyzer.getFirstThrowableOfType(AccessDeniedException.class, causeChain);
            }
            //如果提取到安全异常,则进行处理
            if (ase != null) {
                handleException(request, response, chain, ase);
            } else {
                //没有安全异常,继续抛出
                // Rethrow ServletExceptions and RuntimeExceptions as-is
                if (ex instanceof ServletException) {
                    throw (ServletException) ex;
                }
                else if (ex instanceof RuntimeException) {
                    throw (RuntimeException) ex;
                }
                throw new RuntimeException(ex);
            }
        }
    }
    //处理安全异常
    private void handleException(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
            RuntimeException exception) throws IOException, ServletException {
        //如果是认证异常,由sendStartAuthentication处理
        if (exception instanceof AuthenticationException) {
            sendStartAuthentication(request, response, chain, (AuthenticationException) exception);
        }
        //如果是访问拒绝异常,由访问拒绝处理类的handle处理
        else if (exception instanceof AccessDeniedException) {
            if (authenticationTrustResolver.isAnonymous(SecurityContextHolder.getContext().getAuthentication())) {
                sendStartAuthentication(request, response, chain, new InsufficientAuthenticationException(
                        "Full authentication is required to access this resource"));
            }
            else {
                accessDeniedHandler.handle(request, response, (AccessDeniedException) 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
        //首先把SecurityContext中的认证实体置空
        SecurityContextHolder.getContext().setAuthentication(null);
        //通过cache保存当前的请求信息(分析RequestCacheAwareFilter时再深入)
        requestCache.saveRequest(request, response);
        logger.debug("Calling Authentication entry point.");
        //由认证入口点开始处理
        authenticationEntryPoint.commence(request, response, reason);
    }

这里补充一下
authenticationEntryPoint是由配置http标签时,通过什么认证入口来决定注入相应的入口点bean的。请看下面的对应关系列表
form-login认证:LoginUrlAuthenticationEntryPoint
http-basic认证:BasicAuthenticationEntryPoint
openid-login认证:LoginUrlAuthenticationEntryPoint
x509认证:Http403ForbiddenEntryPoint


就不一一分析每个EntryPoint了,着重看一下LoginUrlAuthenticationEntryPoint
    //主要目的是完成跳转任务
     //创建该bean时,只注入了loginFormUrl属性,其他类变量均为默认值
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
            throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        String redirectUrl = null;
        //默认为false
        if (useForward) {
            if (forceHttps && "http".equals(request.getScheme())) {
                redirectUrl = buildHttpsRedirectUrlForRequest(httpRequest);
            }

            if (redirectUrl == null) {
                String loginForm = determineUrlToUseForThisRequest(httpRequest, httpResponse, authException);
                RequestDispatcher dispatcher = httpRequest.getRequestDispatcher(loginForm);
                dispatcher.forward(request, response);
                return;
            }
        } else {
            //返回的url为loginFormUrl配置的值,如果未配置,跳转到默认登录页面/spring_security_login
            redirectUrl = buildRedirectUrlToLoginPage(httpRequest, httpResponse, authException);

        }
        redirectStrategy.sendRedirect(httpRequest, httpResponse, redirectUrl);
    }


接着分析访问拒绝类异常的处理过程,看AccessDeniedHandlerImpl的handle方法
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException)
            throws IOException, ServletException {
        if (!response.isCommitted()) {
            //如果配置了access-denied-page属性,跳转到指定的url
            if (errorPage != null) {
                // Put exception into request scope (perhaps of use to a view)
                request.setAttribute(SPRING_SECURITY_ACCESS_DENIED_EXCEPTION_KEY, accessDeniedException);

                // Set the 403 status code.
                response.setStatus(HttpServletResponse.SC_FORBIDDEN);

                // forward to error page.
                RequestDispatcher dispatcher = request.getRequestDispatcher(errorPage);
                dispatcher.forward(request, response);
            //如果没有配置,则直接响应403禁止访问的错误信息到浏览器端
            } else {
                response.sendError(HttpServletResponse.SC_FORBIDDEN, accessDeniedException.getMessage());
            }
        }
    }


通过以上分析,可以大体上认识到ExceptionTranslationFilter主要拦截两类安全异常:认证异常、访问拒绝异常。而且仅仅是捕获FilterSecurityInterceptor、SwitchUserFilter以及自定义拦截器的异常。所以在自定义拦截器时,需要注意在链中的顺序。

在上面分析过程中,有requestCache.saveRequest(request, response);的语句,具体requestCache的用途下篇分析。
分享到:
评论

相关推荐

    spring security 3.1.3 源码含sample源码

    综上,Spring Security 3.1.3源码的分析和学习,可以帮助开发者深入理解Web安全原理,掌握如何利用这个强大的框架来保护应用程序免受攻击。通过对源码的研究,可以更清晰地了解其内部工作方式,从而更好地进行定制化...

    SpringBoot_SpringSecurity-源码.rar

    SpringBoot_SpringSecurity-源码.zip 这个压缩包文件主要包含了SpringBoot集成SpringSecurity的源码分析。SpringBoot是Java开发中一个流行的轻量级框架,它简化了配置和应用部署,使得开发者可以快速搭建应用程序。...

    spring-security3.1源码

    3. **Filter安全链**:Spring Security 的Web安全功能主要通过一系列过滤器实现,这些过滤器构成了安全链。其中关键的过滤器有`DelegatingFilterProxy`、`ChannelProcessingFilter`、`...

    spring security源码分析.pdf

    ### Spring Security 源码分析知识...以上内容涵盖了 Spring Security 3 的源码分析中几个关键点的具体内容。通过对这些内容的深入学习和理解,可以更好地掌握 Spring Security 的工作原理及其在实际项目中的应用技巧。

    spring-security源码,直接引用这个压缩文件即可

    在分析`spring-security 5.0`的源码时,我们可以深入理解其核心机制,帮助我们更好地使用和扩展该框架。 1. **模块结构**: Spring Security 5.0 的源码包含多个模块,如`core`、`config`、`web`等。`core`模块...

    Spring_Security3_源码分析

    通过这些源码分析,我们可以了解到Spring Security是如何在背后工作,保护应用程序免受未经授权的访问。理解这些组件的工作原理对于定制和优化安全配置至关重要,同时也有助于开发者解决潜在的安全问题。

    spring-security-3.2.9的jar包和源码包

    7. **源码分析**:源码包允许开发者深入研究Spring Security的实现细节,了解其内部的工作流程,这对于自定义扩展和调试是非常有价值的。例如,可以通过阅读`AuthenticationManager`和`UserDetailsService`的实现来...

    spring security简单示例

    6. **源码分析**: Spring Security的源码是开源的,你可以深入研究其内部工作原理,了解每个组件是如何协同工作的。这将帮助你更好地理解和定制这个框架。 7. **工具**: - Spring Security的官方文档和教程是...

    SpringSecurity3框架

    源码分析对于深入理解Spring Security的工作原理至关重要。通过阅读源码,开发者可以了解每个组件如何协同工作,以及如何根据特定需求定制框架。例如,你可以研究`FilterSecurityInterceptor`如何调用`...

    使用SpringSecurity3用户验证几点体会(异常信息,验证码)

    6. **源码分析**: 分析`ValidateCodeAuthenticationFilter`的源码可以帮助我们理解验证码验证的整个流程,包括何时生成验证码、如何将其与用户的会话关联、以及如何在认证过程中验证它。这有助于我们定制自己的...

    Spring_security 3.x 登录权限测试模块.以及源码.

    通过学习和分析这些源代码,你可以深入了解Spring Security的工作原理,以及如何将其集成到你的应用程序中以实现安全控制。对于开发人员来说,理解这些核心概念和组件非常重要,因为它们构成了Spring Security强大...

    菜鸟-手把手教你把Acegi应用到实际项目中(1.2)

    Acegi是Spring Security的前身,它是一个用于Java平台的安全框架,专为Spring应用程序设计。本教程将引导初学者逐步了解如何在实际项目中应用Acegi安全框架,以便为你的Web应用提供强大的身份验证和授权功能。 首先...

    Acegi 各过滤的解析(一)

    Acegi Security是Spring框架早期的一个安全模块,它提供了全面的认证和授权功能,为Java企业级应用提供了强大的安全控制。本文将重点解析Acegi Security中的各个过滤器,这些过滤器在保护应用程序的安全方面起着至关...

Global site tag (gtag.js) - Google Analytics