Spring Security 认证处理流程源码

一、UsernamePasswordAuthenticationFilter

org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter

第一个验证处理过滤器类,负责处理表单登录请求获,取请求中带的username、password,使用username、password构建org.springframework.security.authentication.UsernamePasswordAuthenticationToken
从UsernamePasswordAuthenticationToken这个对象从继承书上看,实际上是Authentication接口的实现,Authentication接口实际上是封装了认证信息。

UsernamePasswordAuthenticationToken

UsernamePasswordAuthenticationFilter用username、password构建UsernamePasswordAuthenticationToken的时候:
1、把用户名和密码都设置到自己本地变量上
2、super(null);父类构造函数需要传一组权限进来,但是执行到当前代码的时候,还没有进行过身份认证,不知道这个用户的权限是什么,所以这里是null
3、setAuthenticated(false);表示前面存储进去的信息是否经过身份认证,false表示没有

具体代码:

public UsernamePasswordAuthenticationToken(Object principal, Object credentials) {
        // 父类构造函数需要传一组权限进来,但是执行到当前代码的时候,还没有进行过身份认证,不知道这个用户的权限是什么,所以这里是null
        super(null);
        // 把用户名和密码都设置到自己本地变量上
        this.principal = principal;
        this.credentials = credentials;
        // 表示前面存储进去的信息是否经过身份认证,false表示没有
        setAuthenticated(false);
    }
setDetails
org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#setDetails(HttpServletRequest,UsernamePasswordAuthenticationToken)

把请求的信息设置到UsernamePasswordAuthenticationToken里面,包括发请求的ip、session等

二、AuthenticationProvider

然后开始调用AuthenticationManagerorg.springframework.security.authentication.AuthenticationManager,AuthenticationManager本身并不包含验证的逻辑,它的作用是用来管理AuthenticationProvider org.springframework.security.authentication.ProviderManager ,实现了AuthenticationManager。

ProviderManager.authenticate(Authentication authentication)方法
里面有一个for循环,getProviders()拿到所有的AuthenticationProvider接口,真正的校验是写在AuthenticationProvider里面的。

为什么是for循环?因为不同的登录方式,它的认证逻辑是不一样的。用户名密码登录验密码。第三方登录,是不需要密码的,两种登录,逻辑不一样,spring security 提供两个AuthenticationProvider。

AuthenticationManager负责把所有的AuthenticationProvider收集起来,收集之后,挨个比对该AuthenticationProvider支不支持对应的登录方式,即:provider.supports(toTest) ,如果不支持,继续比对下一个;支持,执行真正的校验逻辑 result = provider.authenticate(authentication);

AuthenticationManager校验AuthenticationProvider支持的登录方式
result = provider.authenticate(authentication);

主要的校验逻辑在调抽象类org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider的Authentication authenticate(Authentication authentication)方法里面的authenticate(Authentication authentication)。

retrieveUser()方法

retrieveUser()方法获取UserDetails对象,retrieveUser()是一个抽象方法,它的实现org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser()中有:

UserDetails loadedUser ==this.getUserDetailsService().loadUserByUsername(username);

实际上是在调UserDetailsService接口的实现来获取UserDetailsService,就和前面的自定义用户逻辑对接上了,如果拿到了用户信息,就有一个(preAuthenticationChecks.check(user););

预检查

preAuthenticationChecks.check(user);的实现是一个内部类:

org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.DefaultPreAuthenticationChecks.check(user);

这里面做了三个检查,返回的是UserDetails的实现,而UserDetails里面有四个Boolean方法分别判断用户是否可用等,这里检查其中三个,并抛出对应账户锁定、账户过期异常。

additionalAuthenticationChecks
additionalAuthenticationChecks(user,(UsernamePasswordAuthenticationToken) authentication);附加的检查,在抽象类中是一个抽象方法,在DaoAuthenticationProvider中具体的实现,用PasswordEncoder校验密码是否匹配。

后检查

如果前面的都通过后再有一个,postAuthenticationChecks.check(user);后检查,DefaultPostAuthenticationChecks实现,检查四个Boolean里面的最后一个,所有的检查都通过,表明用户认证是成功的,然后在创建一个Authentication。

创建Authentication
createSuccessAuthentication(principalToReturn, authentication, user);

重新实例一个UsernamePasswordAuthenticationToken,不过构造方法不一样了,传入了Authentication,setAuthenticated(true);认证已经通过

    /**
     * This constructor should only be used by <code>AuthenticationManager</code> or
     * <code>AuthenticationProvider</code> implementations that are satisfied with
     * producing a trusted (i.e. {@link #isAuthenticated()} = <code>true</code>)
     * authentication token.
     *
     * @param principal
     * @param credentials
     * @param authorities
     */
    public UsernamePasswordAuthenticationToken(Object principal, Object credentials,
            Collection<? extends GrantedAuthority> authorities) {
        super(authorities);
        this.principal = principal;
        this.credentials = credentials;
        super.setAuthenticated(true); // must use super, as we override
    }

最后Authentication再返回会UsernamePasswordAuthenticationFilter调登陆成功的自定义方法,org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.successfulAuthentication(HttpServletRequest, HttpServletResponse, FilterChain, Authentication) 和失败的自定义方法。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值