1. 程式人生 > >Shiro learning - 認證流程

Shiro learning - 認證流程

 

Shiro認證流程

在學習認證流程之前,你應該先了解Shiro的基本使用流程

認證

  • 身份認證: 證明使用者是誰。使用者需要提供相關的憑證principals(身份標識)和Credentials (憑證,證明你是這個使用者,可以理解成密碼)
  • Principals: 使用者的屬性,可以有多個。但是至少有一個屬效能唯一使用者
  • Credentials: 證明資訊,密碼或者證書之類的

認證流程

 

  • token傳給Subject.login(Token)。在呼叫login方法時候,內部完成了認證和授權
  • 實際上的認證是由SecurityManager呼叫Authenticator認證器
  • Authenticator認證器在呼叫實際的Realms的時候根據配置的Authentication Strategy認證策略規則判斷是否認證成功

詳細的認證流程

Subject是個介面,實際上的

login(AuthenticationToken var1)是由子類DelegatingSubject實現的
 1 public void login(AuthenticationToken token) throws AuthenticationException {
 2         this.clearRunAsIdentitiesInternal();
 3
Subject subject = this.securityManager.login(this, token); 4 String host = null; 5 PrincipalCollection principals; 6 if (subject instanceof DelegatingSubject) { 7 DelegatingSubject delegating = (DelegatingSubject)subject; 8 principals = delegating.principals;
9 host = delegating.host; 10 } else { 11 principals = subject.getPrincipals(); 12 } 13 14 if (principals != null && !principals.isEmpty()) { 15 this.principals = principals; 16 this.authenticated = true; 17 if (token instanceof HostAuthenticationToken) { 18 host = ((HostAuthenticationToken)token).getHost(); 19 } 20 21 if (host != null) { 22 this.host = host; 23 } 24 25 Session session = subject.getSession(false); 26 if (session != null) { 27 this.session = this.decorate(session); 28 } else { 29 this.session = null; 30 } 31 32 } else { 33 String msg = "Principals returned from securityManager.login( token ) returned a null or empty value. This value must be non null and populated with one or more elements."; 34 throw new IllegalStateException(msg); 35 } 36 }

可以看到在第三行中

呼叫了ScurityManager.login

因此可以證明subject只是儲存使用者資訊,使用者的認證和授權其實是通過SecurityManager呼叫認證器和授權器實現的。可以把SecurityManager理解成一箇中央排程器。

SecurityManager是一個介面,整合Authenticator, Authorizer, SessionManager 

public interface SecurityManager extends Authenticator, Authorizer, SessionManager {
    Subject login(Subject var1, AuthenticationToken var2) throws AuthenticationException;

    void logout(Subject var1);

    Subject createSubject(SubjectContext var1);
}

SecurityManager有login方法,因此我們可以找找SecurityManager的實現類

我們可以在DefaultSecurityManager中找到Login()方法

 1  public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException {
 2         AuthenticationInfo info;//儲存使用者的認證資訊和授權資訊
 3         try {
 4             info = this.authenticate(token);//劃重點
 5         } catch (AuthenticationException var7) {
 6             AuthenticationException ae = var7;
 7 
 8             try {
 9                 this.onFailedLogin(token, ae, subject);
10             } catch (Exception var6) {
11                 if (log.isInfoEnabled()) {
12                     log.info("onFailedLogin method threw an exception.  Logging and propagating original AuthenticationException.", var6);
13                 }
14             }
15 
16             throw var7;
17         }
18 
19         Subject loggedIn = this.createSubject(token, info, subject);
20         this.onSuccessfulLogin(token, info, loggedIn);
21         return loggedIn;
22     }

第四行呼叫了authenticate(token).這個方法是SecurityManager的一個實現類AuthenticatingSecurityManager.java實現的,也是DefaultSecurityManager的父類

1  private Authenticator authenticator = new ModularRealmAuthenticator();//認證器
2 
3    public AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException {
4         return this.authenticator.authenticate(token);
5     }

可以看到最終認證器的實現是 ModularRealmAuthenticator

總結: Shiro通過呼叫Subject的子類DelegatingSubject 的login(AuthenticationToken token)完成使用者的認證和授權。實際上的認證是由SecurityManager的預設子類DefaultSecurityManager中的Login方法呼叫SecurityManager的另外一個子類AuthenticatingSecurityManager也同時是DefaultSecurityManager的父類authenticate(AuthenticationToken token)完成認證。並且最終的認證器型別是ModualRealmAuthenticator