Spring Security 之 AbstractAuthenticationProcessingFilter 源码解析

 SpringSecurity对Spring Web项目提供支持,AbstractAuthenticationProcessingFilte 作为验证请求入口的。

AbstractAuthenticationProcessingFilter 继承自 GenericFilterBean,而 GenericFilterBean spring 框架中的过滤器类,实现了接口 javax.servlet.Filter

public abstract class AbstractAuthenticationProcessingFilter
 extends GenericFilterBean implements ApplicationEventPublisherAware, MessageSourceAware {

 AbstractAuthenticationProcessingFilte 成员变量

    protected ApplicationEventPublisher eventPublisher;
    protected AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
    private AuthenticationManager authenticationManager;
    protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
    private RememberMeServices rememberMeServices = new NullRememberMeServices();
    private RequestMatcher requiresAuthenticationRequestMatcher;
    private boolean continueChainBeforeSuccessfulAuthentication = false;
    private SessionAuthenticationStrategy sessionStrategy = new NullAuthenticatedSessionStrategy();
    private boolean allowSessionCreation = true;
    private AuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
    private AuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();

 AbstractAuthenticationProcessingFilter的主要职责和依赖组件

abstractAuthenticationProcessingFilter的职责也就非常明确——处理所有HTTP Request和Response对象,并将其封装成AuthenticationMananger可以处理的Authentication。并且在身份验证成功或失败之后将对应的行为转换为HTTP的Response。同时还要处理一些Web特有的资源比如Session和Cookie。总结成一句话,就是替AuthenticationMananger把所有和Authentication没关系的事情全部给包圆了。

 

 AbstractAuthenticationProcessingFilter为了完成组织上交代的与浏览器和HTTP请求的验证任务,它将大任务拆成了几个子任务并交给了以下组件完成

  • AuthenticationManager用于处理身份验证的核心逻辑;
  • AuthenticationSuccessHandler用于处理验证成功的后续流程;
  • AuthenticationFailureHandler用于处理失败的后续流程;
  • 在验证成功后发布一个名为InteractiveAuthenticationSuccessEvent的事件通知给到应用上下文,用于告知身份验证已经成功;
  • 因为是基于浏览器所以相关的会话管理行为交由 SessionAuthenticationStrategy来进行实现。
  • 文档上还有一点没有写出来的是,如果用户开启了类似“记住我”之类的免密码登录,AbstractAuthenticationProcessingFilter还有一个名为RememberMeServices来进行管理。

流程分析

因为 AbstractAuthenticationProcessingFilter 为本质上是一个 servlet 过滤器,因此找到其入口函数 doFilter()

try代码快中的 --> 1 处代码表示该处会调用 attemptAuthentication()方法进行身份校验处理。attemptAuthentication()方法本体如下所示:

public abstract Authentication attemptAuthentication(HttpServletRequest request,
            HttpServletResponse response) throws AuthenticationException, IOException,
            ServletException;

该方法是个等待子类实现的虚拟方法,对于用户帐号密码的校验在该方法中进行,最后放回的是Authentication 对象。

catch 代码块中的 --> 2 和 --> 3 处代码表示身份校验失败之后调用方法 unsuccessfulAuthentication(),该方法本体如下所示:

protected void unsuccessfulAuthentication(HttpServletRequest request,
            HttpServletResponse response, AuthenticationException failed)
            throws IOException, ServletException {
        SecurityContextHolder.clearContext();

        if (logger.isDebugEnabled()) {
            logger.debug("Authentication request failed: " + failed.toString(), failed);
            logger.debug("Updated SecurityContextHolder to contain null Authentication");
            logger.debug("Delegating to authentication failure handler " + failureHandler);
        }

        rememberMeServices.loginFail(request, response);

        failureHandler.onAuthenticationFailure(request, response, failed);
    }

该方法中最重要的一条语句是failureHandler.onAuthenticationFailure(request, response, failed);,表明验证身份信息失败之后调用类 failureHandleronAuthenticationFailure() 方法。而 failureHandlerAuthenticationFailureHandler 的实例变量。

  • --> 4 处代码表示验证身份信息成功后,调用 successfulAuthentication() 方法,其方法本体如下:
    protected void successfulAuthentication(HttpServletRequest request,
            HttpServletResponse response, FilterChain chain, Authentication authResult)
            throws IOException, ServletException {

        if (logger.isDebugEnabled()) {
            logger.debug("Authentication success. Updating SecurityContextHolder to contain: "
                    + authResult);
        }

        SecurityContextHolder.getContext().setAuthentication(authResult);

        rememberMeServices.loginSuccess(request, response, authResult);

        // Fire event
        if (this.eventPublisher != null) {
            eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(
                    authResult, this.getClass()));
        }

        successHandler.onAuthenticationSuccess(request, response, authResult);
    }

其中,最重要的一行代码是 successHandler.onAuthenticationSuccess(request, response, authResult);,表示身份验证成功后调用 successHandleronAuthenticationSuccess 方法。而 successHandlerAuthenticationSuccessHandler 的实现变量。

 


接下来我们讨论几个问题。

问题1. 怎么判断当前的请求是需要被验证访问的?

在正式进行身份之前,doFilter会通过Security中的MatcherRequest。尝试查找是否有匹配记录。
访问控制的代码:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                // inde.html对应的url允许所任人访问
                .antMatchers("/").permitAll()
                // user.html对应的url,则需要用户有USER的角色才可以访问
                .antMatchers("/user").hasRole("USER")
                .and()
                .formLogin();
    }

 其中的matcher的规则便会在这个流程中预先被检查,如果需要进行身份验证则会进行写一个阶段:对请求进行必要的身份验证。

问题2. 如何进行身份验证?

doFilter中通过调用自己的attemptAuthentication方法,但并不进行身份验证的逻辑处理,而是委托AuthenticationManager去完成相关的身份验证流程。AbstractAuthenticationProcessingFilter将HttpServletRequest包装成了Authentication对象与核心的AuthenticationManager进行交互。这样的设计可以使AuthenticationManager不感知外部的Web环境,从而使Security不仅可以支持Web应用,同时也可以被所有Java应用进行使用——只要客制化外部参与并将其封装成Authentication与AuthenticationManager的进行身份验证。

这里还需要注意的是在AuthenticationManager中实际完成身份验证任务并不是AuthenticationManager它自己身。而是将相关的任务针对每一种身份验证协议的AuthenticationProvider去完成相关的身份验证工作。

 

 

 

  • 9
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring Security 是一个功能强大且广泛使用的安全框架,用于保护 Java 应用程序的身份验证和授权。它提供了一套全面的安全解决方案,包括认证、授权、攻击防护等功能。 Spring Security源码是开源的,可以从官方仓库(https://github.com/spring-projects/spring-security)获取到。在源码中,主要包含以下几个关键模块: 1. 核心模块(Core):提供了基本的认证和授权功能,包括用户身份认证、访问控制等。核心模块的源码位于 `spring-security-core` 包下。 2. Web 模块(Web):提供了与 Web 应用程序集成的相关功能,如基于 URL 的授权、Web 表单登录、记住我功能等。Web 模块的源码位于 `spring-security-web` 包下。 3. 配置模块(Config):提供了基于 Java 配置和 XML 配置的方式来配置 Spring Security。配置模块的源码位于 `spring-security-config` 包下。 4. 测试模块(Test):提供了用于测试 Spring Security 的工具和辅助类。测试模块的源码位于 `spring-security-test` 包下。 在源码中,你可以深入了解 Spring Security 的内部工作原理、各个组件之间的协作关系以及具体的实现细节。可以通过跟踪调试源码,了解每个功能是如何实现的,从而更好地理解和使用 Spring Security。 请注意,Spring Security源码是非常庞大且复杂的,需要一定的时间和精力去深入研究。建议在阅读源码之前,先对 Spring Security 的基本概念和使用方法有一定的了解,这样会更有助于理解源码中的内容。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值