【微服务|Spring Security⑪】spring security认证流程之AuthenticationProvider

流程图
在这里插入图片描述

认证过程分析:

1.用户提交用户名 密码被 SecurityFilterChain 中的UsernamePasswordAuthenticationFilter 过滤器获取到, 封装为请求Authentication ,通常情况下是UsernamePasswordAuthenticationToken这个实现类。

2.然后过滤器将Authentication提交至认证管理器(AuthenticationManager)进行认证

3.认证成功后,AuthenticationManager身份管理器返回一个被填充满了信息的(包括上面提到的权限信息, 身份信息,细节信息,但密码通常会被移除)Authentication实例。

4.SecurityContextHolder安全上下文容器将第3步填充了信息的Authentication ,通过 SecurityContextHolder.getContext().setAuthentication(…)方法,设置到其中。

可以看出AuthenticationManager接口(认证管理器)是认证相关的核心接口 ,也是发起认证的出发点,它的实现类为ProviderManager。而SpringSecurity支持多种认证方式,因此ProviderManager维护着一个List列表,存放多种认证方式,最终实际的认证工作是由AuthenticationProvider完成的。web表单的对应的AuthenticationProvider实现类为DaoAuthenticationProvider,它的内部又维护着一个UserDetailsService负责UserDetails的获取。最终AuthenticationProvider将UserDetails填充至Authentication。

认证核心组件的大体关系如下:
在这里插入图片描述

4.2.2.1 AuthenticationProvider

通过前面的Spring Security认证流程我们得知,认证管理器(AuthenticationManager)委托 AuthenticationProvider 完成认证工作。

AuthenticationProvider是一个接口 ,定义如下:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.security.authentication;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;

public interface AuthenticationProvider {
    
    
    Authentication authenticate(Authentication var1) throws AuthenticationException;

    boolean supports(Class<?> var1);
}

authenticate()方法定义了认证的实现过程,它的参数是一个Authentication ,里面包含了登录用户所提交的用户 密码等。而返回值也是一个Authentication ,这个Authentication则是在认证成功后,将用户的权限及其他信息重新组装后生成。

Spring Security中维护着一个List列表,存放多种认证方式,不同的认证方式使用不同的AuthenticationProvider。如使用用户名密码登录时,使用AuthenticationProviderl ,短信登录时使用 Authentication Provider2等等这样的例子很多。

每个AuthenticationProvider需要实现supports ()方法来表明自己支持的认证方式,如我们使用表单方式认证, 在提交请求时Spring Security会生成UsernamePasswordAuthenticationToken ,它是一个Authentication ,里面封装着用户提交的用户名、密码信息。

而对应哪个AuthenticationProvider来处理它?

我们在 DaoAuthenticationProvider的基类 AbstractUserDetailsAuthenticationProvider 发现以下代码:

    public boolean supports(Class<?> authentication) {
    
    
        return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
    }//149行

也就是说当web表单提交用户名密码时,Spring Security由DaoAuthenticationProvider处理。

最后,我们来看一下Authentication(认证信息)的结构,它是一个接口 ,我们之前提到的 UsernamePasswordAuthenticationToken就是它的实现之一:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.security.core;

import java.io.Serializable;
import java.security.Principal;
import java.util.Collection;

public interface Authentication extends Principal, Serializable {
    
    //1
    Collection<? extends GrantedAuthority> getAuthorities();//2

    Object getCredentials();//3

    Object getDetails();//4

    Object getPrincipal();//5

    boolean isAuthenticated();

    void setAuthenticated(boolean var1) throws IllegalArgumentException;
}

(1 ) Authentication是spring security包中的接口,直接继承自Principal类,而Principal是位于 java.security 包中的。它是表示着一个抽象主体身份,任何主体都有一个名称,因此包含一个getName()方法。

(2 ) getAuthorities(),权限信息列表,默认是GrantedAuthority接口的一些实现类,通常是代表权限信息的一系列字符串。

(3 ) getCredentials(),凭证信息,用户输入的密码字符串,在认证过后通常会被移除,用于保障安全。

(4 ) getDetails(),细节信息,web应用中的实现接口通常为WebAuthenticationDetails ,它记录了访问者的ip地址和sessionld的值。

(5 ) getPrincipal(),身份信息,大部分情况下返回的是UserDetails接口的实现类,UserDetails代表用户的详细信息,从Authentication中取出来的UserDetails就是当前登录用户信息,它也是框架中的常用接口之一。

附参考代码:

/*
 * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 */

package java.security;

import javax.security.auth.Subject;

/**
 * This interface represents the abstract notion of a principal, which
 * can be used to represent any entity, such as an individual, a
 * corporation, and a login id.
 *
 * @see java.security.cert.X509Certificate
 *
 * @author Li Gong
 */
public interface Principal {
    
    

    /**
     * Compares this principal to the specified object.  Returns true
     * if the object passed in matches the principal represented by
     * the implementation of this interface.
     *
     * @param another principal to compare with.
     *
     * @return true if the principal passed in is the same as that
     * encapsulated by this principal, and false otherwise.
     */
    public boolean equals(Object another);

    /**
     * Returns a string representation of this principal.
     *
     * @return a string representation of this principal.
     */
    public String toString();

    /**
     * Returns a hashcode for this principal.
     *
     * @return a hashcode for this principal.
     */
    public int hashCode();

    /**
     * Returns the name of this principal.
     *
     * @return the name of this principal.
     */
    public String getName();

    /**
     * Returns true if the specified subject is implied by this principal.
     *
     * <p>The default implementation of this method returns true if
     * {@code subject} is non-null and contains at least one principal that
     * is equal to this principal.
     *
     * <p>Subclasses may override this with a different implementation, if
     * necessary.
     *
     * @param subject the {@code Subject}
     * @return true if {@code subject} is non-null and is
     *              implied by this principal, or false otherwise.
     * @since 1.8
     */
    public default boolean implies(Subject subject) {
    
    
        if (subject == null)
            return false;
        return subject.getPrincipals().contains(this);
    }
}

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.security.core;

import java.io.Serializable;

public interface GrantedAuthority extends Serializable {
    
    
    String getAuthority();
}

猜你喜欢

转载自blog.csdn.net/CSDN_SAVIOR/article/details/125683231