Authentication介面及子類

2021-12-30 21:00:02

繼承關係圖

在這裡插入圖片描述

Authentication英文翻譯過來就是身份驗證,驗證的意思。Authentication在SpringSecutiry架構中佔有核心地位,在org.springframework.security.core包中。定義了身份驗證成功前和後通常用此介面儲存使用者基礎資訊後續儲存:

// 當前登入人的詳細
// Authentication是SpringSecurity中認證的主體,包含主體許可權列表、主體憑據、主體詳細資訊,以及主體是否驗證成功等資訊
public interface Authentication extends Principal, Serializable {
    // 許可權集合
    Collection<? extends GrantedAuthority> getAuthorities();
    // 憑證 一般情況下都是指的是密碼
    Object getCredentials();
    // 使用者資訊詳情
    Object getDetails();
    // 一般指使用者名稱
    Object getPrincipal();
    // 否認證成功
    boolean isAuthenticated();
    // 設定是否認證成功
    void setAuthenticated(boolean var1) throws IllegalArgumentException;
}

在Spring原始碼中一般介面後面肯定是對應的抽象類,對介面功能進行擴充套件,AbstractAuthenticationToken抽象類則是對==Authentication介面功能進行了擴充套件和完善,其中CredentialsContainer也非常的重要,在後期認證過程中有著承上啟下的作用 ,都同屬於org.springframework.security.core包下:

// 根據介面名稱翻譯則是憑證容器
// 可以理解為實現了此介面的類則會成為容納認證完後的憑證資訊
public interface CredentialsContainer {
    // 擦除憑據方法
    void eraseCredentials();
}
// 通過抽象類的名稱得知是通過token認證
public abstract class AbstractAuthenticationToken implements Authentication, CredentialsContainer {
    // 容納許可權的集合
    private final Collection<GrantedAuthority> authorities;
    // 使用者詳情物件
    private Object details;
    // 預設是沒有認證
    private boolean authenticated = false;
 
    // 構造器  
    // authorities 許可權集合
    public AbstractAuthenticationToken(Collection<? extends GrantedAuthority> authorities) {
        // 如果許可權集合為空
        // 建立一個空集合
        if (authorities == null) {
            this.authorities = AuthorityUtils.NO_AUTHORITIES;
        } else {
        // 迭代authorities許可權集合
        // 初始化authorities
            Iterator var2 = authorities.iterator();

            GrantedAuthority a;
            do {
                if (!var2.hasNext()) {
                    ArrayList<GrantedAuthority> temp = new ArrayList(authorities.size());
                    temp.addAll(authorities);
                    this.authorities = Collections.unmodifiableList(temp);
                    return;
                }

                a = (GrantedAuthority)var2.next();
            } while(a != null);

            throw new IllegalArgumentException("Authorities collection cannot contain any null elements");
        }
    }

    // 獲取許可權
    public Collection<GrantedAuthority> getAuthorities() {
        return this.authorities;
    }
  
   // 獲取名稱
    public String getName() {
        if (this.getPrincipal() instanceof UserDetails) {
            return ((UserDetails)this.getPrincipal()).getUsername();
        } else if (this.getPrincipal() instanceof AuthenticatedPrincipal) {
            return ((AuthenticatedPrincipal)this.getPrincipal()).getName();
        } else if (this.getPrincipal() instanceof Principal) {
            return ((Principal)this.getPrincipal()).getName();
        } else {
            return this.getPrincipal() == null ? "" : this.getPrincipal().toString();
        }
    }
    
    // 返回當前認證狀態
    public boolean isAuthenticated() {
        return this.authenticated;
    }
    // 設定當前認證狀態
    public void setAuthenticated(boolean authenticated) {
        this.authenticated = authenticated;
    }
    
    // 返回詳細資訊
    public Object getDetails() {
        return this.details;
    }
 
    // 設定詳細資訊
    public void setDetails(Object details) {
        this.details = details;
    }

    // 擦除憑證
    public void eraseCredentials() {
        // 密碼
        this.eraseSecret(this.getCredentials());
        // 使用者名稱
        this.eraseSecret(this.getPrincipal());
        // 詳情
        this.eraseSecret(this.details);
    }
    
    // 擦除憑證方法
    private void eraseSecret(Object secret) {
        // secret 是否是CredentialsContainer的子類
        if (secret instanceof CredentialsContainer) {
            // 使用擦除憑證的具體實現方法對憑證進行擦除
            ((CredentialsContainer)secret).eraseCredentials();
        }
    }

    public boolean equals(Object obj) {
        if (!(obj instanceof AbstractAuthenticationToken)) {
            return false;
        } else {
            AbstractAuthenticationToken test = (AbstractAuthenticationToken)obj;
            if (!this.authorities.equals(test.authorities)) {
                return false;
            } else if (this.details == null && test.getDetails() != null) {
                return false;
            } else if (this.details != null && test.getDetails() == null) {
                return false;
            } else if (this.details != null && !this.details.equals(test.getDetails())) {
                return false;
            } else if (this.getCredentials() == null && test.getCredentials() != null) {
                return false;
            } else if (this.getCredentials() != null && !this.getCredentials().equals(test.getCredentials())) {
                return false;
            } else if (this.getPrincipal() == null && test.getPrincipal() != null) {
                return false;
            } else if (this.getPrincipal() != null && !this.getPrincipal().equals(test.getPrincipal())) {
                return false;
            } else {
                return this.isAuthenticated() == test.isAuthenticated();
            }
        }
    }

    public int hashCode() {
        int code = 31;

        GrantedAuthority authority;
        for(Iterator var2 = this.authorities.iterator(); var2.hasNext(); code ^= authority.hashCode()) {
            authority = (GrantedAuthority)var2.next();
        }

        if (this.getPrincipal() != null) {
            code ^= this.getPrincipal().hashCode();
        }

        if (this.getCredentials() != null) {
            code ^= this.getCredentials().hashCode();
        }

        if (this.getDetails() != null) {
            code ^= this.getDetails().hashCode();
        }

        if (this.isAuthenticated()) {
            code ^= -37;
        }

        return code;
    }

    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(super.toString()).append(": ");
        sb.append("Principal: ").append(this.getPrincipal()).append("; ");
        sb.append("Credentials: [PROTECTED]; ");
        sb.append("Authenticated: ").append(this.isAuthenticated()).append("; ");
        sb.append("Details: ").append(this.getDetails()).append("; ");
        if (!this.authorities.isEmpty()) {
            sb.append("Granted Authorities: ");
            int i = 0;

            GrantedAuthority authority;
            for(Iterator var3 = this.authorities.iterator(); var3.hasNext(); sb.append(authority)) {
                authority = (GrantedAuthority)var3.next();
                if (i++ > 0) {
                    sb.append(", ");
                }
            }
        } else {
            sb.append("Not granted any authorities");
        }

        return sb.toString();
    }
}

下面我們就說說Authentication具體的子類實現,通過不同方式認證時,使用的不同的實現類儲存認證成功或待認證的使用者資訊:

UsernamePasswordAuthenticationToken

UsernamePasswordAuthenticationToken(位於org.springframework.security.authentication包下) 通過類名可以的看出來,使用者名稱密碼方式進行認證。就是我們見的最多的認證方式通過使用者名稱密碼進行登入。咱們話不多說看看具體實現:

public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {
    // 序列化id
    private static final long serialVersionUID = 530L;
    // 一般指的是使用者名稱
    private final Object principal;
    // 一般指的是密碼
    private Object credentials;

    // 構造器
    // principal  一般指的是使用者名稱
    // credentials  一般指的是密碼
    public UsernamePasswordAuthenticationToken(Object principal, Object credentials) {
        // 初始化父類別構造 許可權集合為空
        super((Collection)null);
        this.principal = principal;
        this.credentials = credentials;
        // 設定是否已認證 預設為false
        this.setAuthenticated(false);
    }
     
    // 構造器
     // principal  一般指的是使用者名稱
    // credentials  一般指的是密碼
    // authorities 許可權
    public UsernamePasswordAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
       // // 初始化父類別構造 許可權集合
        super(authorities);
        this.principal = principal;
        this.credentials = credentials;
        // 設定父類別方法表示已經認證
        super.setAuthenticated(true);
    }
    
    // 獲取密碼
    public Object getCredentials() {
        return this.credentials;
    }
    // 獲取使用者名稱
    public Object getPrincipal() {
        return this.principal;
    }
    // 設定是否已認證 預設為false
    public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
        // 如果為true
        // 丟擲非法引數異常
        if (isAuthenticated) {
            throw new IllegalArgumentException("Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
        } else {
            // 設定父類別是否已認證
            super.setAuthenticated(false);
        }
    }
    // 擦除憑證
    public void eraseCredentials() {  
        // 呼叫父類別方法
        super.eraseCredentials();
        // 將密碼設定為空
        this.credentials = null;
    }
}

TestingAuthenticationToken

TestingAuthenticationToken(位於org.springframework.security.authentication),第一次看到這類名感覺就是用於測試認證使用的類,看了看原始碼確實沒有多少東西:

public class TestingAuthenticationToken extends AbstractAuthenticationToken {
    // 序列號id
    private static final long serialVersionUID = 1L;
    // 一般指密碼
    private final Object credentials;
     // 一般指使用者名稱
    private final Object principal;
   
    // 構造器 
    // principal
    // credentials
    public TestingAuthenticationToken(Object principal, Object credentials) {
        // 初始化父類別構造器 
        super((Collection)null);
        this.principal = principal;
        this.credentials = credentials;
    }

    // 構造器
    public TestingAuthenticationToken(Object principal, Object credentials, String... authorities) {
        this(principal, credentials, AuthorityUtils.createAuthorityList(authorities));
    }
    // 構造器 
    // principal
    // credentials
    // authorities
    public TestingAuthenticationToken(Object principal, Object credentials, List<GrantedAuthority> authorities) {
        // 初始化父類別許可權構造器
        super(authorities);
        this.principal = principal;
        this.credentials = credentials;
        // 將父類別已認證狀態改為true
        this.setAuthenticated(true);
    }

    public Object getCredentials() {
        return this.credentials;
    }

    public Object getPrincipal() {
        return this.principal;
    }
}

看了幾個認證方式的實現類都會有基本的兩個構造器,一個初始化已認證狀態為false,預設父類別就是false,一個初始化已認證狀態為true,感覺一個就是認證前呼叫儲存待認證使用者資訊,另一個是認證成功後跟新當前使用者資訊。