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(); 3Subject 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