(六)Spring Security 认证流程

认证流程

在这里插入图片描述
图片来自于:黑马程序员SpringSecurity认证课程

认证过程:

  1. 用户提交用户名、密码被SecurityFilterChain中的UsernamePasswordAuthenticationFilter 过滤器获取到,封装为请求Authentication,通常情况下是UsernamePasswordAuthenticationToken这个实现类。
  2. 然后过滤器将Authentication提交至认证管理器(AuthenticationManager)进行认证
  3. 认证成功后, AuthenticationManager身份管理器返回一个被填充满了信息的(包括上面提到的权限信息,身份信息,细节信息,但密码通常会被移除) Authentication 实例。
  4. SecurityContextHolder 安全上下文容器将第3步填充了信息的 Authentication ,通过SecurityContextHolder.getContext().setAuthentication(…)方法,设置到其中。可以看出AuthenticationManager接口(认证管理器)是认证相关的核心接口,也是发起认证的出发点,它
    的实现类为ProviderManager。而Spring Security支持多种认证方式,因此ProviderManager维护着一个
    List 列表,存放多种认证方式,最终实际的认证工作是由
    AuthenticationProvider完成的。咱们知道web表单的对应的AuthenticationProvider实现类为
    DaoAuthenticationProvider,它的内部又维护着一个UserDetailsService负责UserDetails的获取。最终
    AuthenticationProvider将UserDetails填充至Authentication。
    认证核心组件的大体关系如下:
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Eg2sjTq4-1599134067449)(F7BB8422DBB94B699003912F92800ECA)]
    图片来自于:黑马程序员SpringSecurity认证课程

知识点认识

Authentication

我们所面对的系统中的用户,在Spring Security中被称为主体(principal)。主体包含了所有能够经过验证而获得系统访问权限的用户、设备或其他系统。主体的概念实际上来自 Java Security,Spring Security通过一层包装将其定义为一个Authentication。

public interface Authentication extends Principal, Serializable {
   
    // 获取主体授权列表
    Collection<? extends GrantedAuthority> getAuthorities();

    // 获取主体凭证,一般为密码
    Object getCredentials();
    
    // 获取主体携带的详细信息
    Object getDetails();
    
    // 获取主体,通常为username
    Object getPrincipal();

    // 获取当前主体是否认证成功
    boolean isAuthenticated();

    // 设置当前主体是否认证成功状态
    void setAuthenticated(boolean var1) throws IllegalArgumentException;
}

AuthenticateProvider

Spring Security 认证的过程其实就是一个构建Authentication的过程。Authentication 在Spring Security的各个AuthenticationProvider中流动,AuthenticationProvider被Spring Security定义为一个验证过程:

public interface AuthenticationProvider {
   
    // 验证完成,成功,返回一个验证完成的Authentication
    Authentication authenticate(Authentication var1) throws AuthenticationException;

    // 是否支持验证当前的Authentication类型
    boolean supports(Class<?> var1);
}

大部分场景下身份验证都是基于用户名和密码进行的,所以Spring Security提供了一个UsernamePasswordAuthenticationToken用于代指这一类证。,每一个登录用户即主体都被包装为一个UsernamePasswordAuthenticationToken,从而在Spring Security的各个AuthenticationProvider中流动。

ProviderManager

一次完整的认证可以包含多个AuthenticationProvider,一般由ProviderManager管理。

public class ProviderManager implements AuthenticationManager, MessageSourceAware, InitializingBean {
   
    private static final Log logger = LogFactory.getLog(ProviderManager.class);
    private AuthenticationEventPublisher eventPublisher;
    
    // AuthenticationProvider 列表
    private List<AuthenticationProvider> providers;
    protected MessageSourceAccessor messages;
    private AuthenticationManager parent;
    private boolean eraseCredentialsAfterAuthentication;

    public ProviderManager(List<AuthenticationProvider> providers) {
   
        this(providers, (AuthenticationManager)null);
    }

    public ProviderManager(List<AuthenticationProvider> providers, AuthenticationManager parent) {
   
        this.eventPublisher = new ProviderManager.NullEventPublisher();
        this.providers = Collections.emptyList();
        this.messages = SpringSecurityMessageSource.getAccessor();
        this.eraseCredentialsAfterAuthentication = true;
        Assert.notNull(providers, "providers list cannot be null");
        this.providers = providers;
        this.parent = parent;
        this.checkState();
    }

    public void afterPropertiesSet() {
   
        this.checkState();
    }

    private void checkState() {
   
        if (this.parent == null && this.providers.isEmpty()) {
   
            throw new IllegalArgumentException("A parent AuthenticationManager or a list of AuthenticationProviders is required");
        }
    }

    // 迭代AuthenticationProvider 列表,进行认证,返回最终结果
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
   
        Class<? extends Authentication> toTest = authentication.getClass();
        AuthenticationException lastException = null;
        AuthenticationException parentException = null;
        Authentication result = null;
        Authentication parentResult = null;
        boolean debug = logger.isDebugEnabled();
        Iterator var8 = this.getProviders().iterator();

        // 迭代
        while(var8.hasNext()) {
   
            AuthenticationProvider provider = (AuthenticationProvider)var8.next();
            // 判断AuthenticationProvider 是否支持当前验证
            if (provider.supports(toTest)) {
   
                if (debug) {
   
                    logger.debug("Authentication attempt using " + provider.getClass().getName());
                }

                try {
   
                    // 执行AuthenticationProvider的认证。
                    result = provider.authenticate(authentication);
                    if (result != null) {
   
                        this.copyDetails(authentication, result);
                        // 有一个验证通过,就返回
                        break;
                    }
                } catch (InternalAuthenticationServiceException | AccountStatusException var13) {
   
                    this.prepareException(
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值