首頁  >  文章  >  後端開發  >  Apache Shiro 使用手冊(二)Shiro 認證

Apache Shiro 使用手冊(二)Shiro 認證

黄舟
黄舟原創
2017-01-18 09:18:332137瀏覽

Apache Shiro 使用手冊(二)Shiro 認證

認證就是驗證使用者身分的過程。在認證過程中,使用者需要提交實體資訊(Principals)和憑證資訊(Credentials)以檢驗使用者是否合法。最常見的「實體/憑證」組合便是「使用者名稱/密碼」組合。 

一、Shiro認證流程 

1、收集實體/憑證資訊 

//Example using most common scenario of username/password pair:  
UsernamePasswordToken token = new UsernamePasswordToken(username, password);  
//”Remember Me” built-in:  
token.setRememberMe(true);

UsernamePasswordToken支援最常見的使用者名稱/密碼的認證機制。同時,由於它實作了RememberMeAuthenticationToken接口,我們可以透過令牌來設定「記住我」的功能。 
但是,「已記住」和「已認證」是有區別的: 
已記住的用戶只是非匿名用戶,你可以透過subject.getPrincipals()取得用戶資訊。但它並非是完全認證通過的用戶,當你存取需要認證用戶的功能時,你仍然需要重新提交認證資訊。
這一區別可以參考亞馬遜網站,網站會默認記住登錄的用戶,再次訪問網站時,對於非敏感的頁面功能,頁面上會顯示記住的用戶信息,但是當你訪問網站帳戶信息時仍然需要再次進行登入認證。 

2、提交實體/憑證資訊 

Subject currentUser = SecurityUtils.getSubject();  
currentUser.login(token);

收集了實體/憑證資訊之後,我們可以透過SecurityUtils工具類,取得目前的用戶,然後透過呼叫login方法提交認證。 

3、認證處理 

try {  
    currentUser.login(token);  
} catch ( UnknownAccountException uae ) { ...  
} catch ( IncorrectCredentialsException ice ) { ...  
} catch ( LockedAccountException lae ) { ...  
} catch ( ExcessiveAttemptsException eae ) { ...  
} ... catch your own ...  
} catch ( AuthenticationException ae ) {  
    //unexpected error?  
}

如果login方法執行完畢且沒有拋出任何異常信息,那麼便認為用戶認證通過。之後在應用程式任意地方呼叫SecurityUtils.getSubject() 都可以取得到目前認證通過的使用者實例,使用subject.isAuthenticated()判斷使用者是否已驗證都會傳回true. 
相反,如果login方法執行過程中拋出異常,那麼將認為認證失敗。 Shiro有著豐富的層次鮮明的異常類別來描述認證失敗的原因,如程式碼範例。

二、登出操作 
登出操作可以透過呼叫subject.logout()來刪除你的登入訊息,如: 

currentUser.logout(); //removes all identifying information and invalidates their session too.

當執行完登出作業後,Session訊息將被清空,subject將被視作為匿名用戶。 

三、認證內部處理機制 
以上,是Shiro認證在應用程式中的處理流程,以下將詳細解說Shiro認證的內部處理機制。 

Apache Shiro 使用手冊(二)Shiro 認證

如上圖,我們透過Shiro架構圖的認證部分,來說明Shiro認證內部的處理順序: 
1、應用程式建構了一個終端使用者認證資訊的AuthenticationToken 實例後,呼叫Subject.login方法。 
2、Sbuject的實例通常是DelegatingSubject類別(或子類別)的實例對象,在認證開始時,會委託應用程式設定的securityManager實例呼叫securityManager.login(token)方法。
3、SecurityManager接受到token(令牌)資訊後會委託內建的Authenticator的實例(通常都是ModularRealmAuthenticator類別的實例)呼叫authenticator.authenticate(token). ModularRealmAuthenticator在認證過程中會對設定的一個或多個Realm實例進行適配,它實際上為Shiro提供了一個可拔插的認證機制。 
4、如果在應用程式中配置了多個Realm,ModularRealmAuthenticator會根據配置的AuthenticationStrategy(認證策略)來進行多Realm的認證過程。在Realm被呼叫後,AuthenticationStrategy將對每一個Realm的結果作出回應。 
註:如果應用程式中僅配置了一個Realm,Realm將被直接呼叫而無需再配置認證策略。 
5、判斷每一個Realm是否支援提交的token,如果支持,Realm將呼叫getAuthenticationInfo(token); getAuthenticationInfo 方法就是實際認證處理,我們透過覆寫Realm的doGetAuthenticationInfo方法來編寫我們自訂的認證處理。 

四、使用多個Realm的處理機制: 

1、Authenticator 
預設實作是ModularRealmAuthenticator,它既支援單一Realm也支援多個Realm。如果僅配置了一個Realm,ModularRealmAuthenticator 會直接呼叫該Realm處理認證訊息,如果配置了多個Realm,它會根據認證策略來適配Realm,找到合適的Realm執行認證資訊。 
自訂Authenticator的設定: 

[main]  
...  
authenticator = com.foo.bar.CustomAuthenticator  
securityManager.authenticator = $authenticator

2、AuthenticationStrategy(认证策略) 
当应用程序配置了多个Realm时,ModularRealmAuthenticator将根据认证策略来判断认证成功或是失败。 
例如,如果只有一个Realm验证成功,而其他Realm验证失败,那么这次认证是否成功呢?如果大多数的Realm验证成功了,认证是否就认为成功呢?或者,一个Realm验证成功后,是否还需要判断其他Realm的结果?认证策略就是根据应用程序的需要对这些问题作出决断。 
认证策略是一个无状态的组件,在认证过程中会经过4次的调用: 

在所有Realm被调用之前

在调用Realm的getAuthenticationInfo 方法之前

在调用Realm的getAuthenticationInfo 方法之后

在所有Realm被调用之后

认证策略的另外一项工作就是聚合所有Realm的结果信息封装至一个AuthenticationInfo实例中,并将此信息返回,以此作为Subject的身份信息。 
Shiro有3中认证策略的具体实现: 

AtLeastOneSuccessfulStrategy     只要有一个(或更多)的Realm验证成功,那么认证将被视为成功    

FirstSuccessfulStrategy     第一个Realm验证成功,整体认证将被视为成功,且后续Realm将被忽略    

AllSuccessfulStrategy     所有Realm成功,认证才视为成功    

ModularRealmAuthenticator 内置的认证策略默认实现是AtLeastOneSuccessfulStrategy 方式,因为这种方式也是被广泛使用的一种认证策略。当然,你也可以通过配置文件定义你需要的策略,如: 

[main]  
...  
authcStrategy = org.apache.shiro.authc.pam.FirstSuccessfulStrategy  
securityManager.authenticator.authenticationStrategy = $authcStrategy  
...

3、Realm的顺序 
由刚才提到的认证策略,可以看到Realm在ModularRealmAuthenticator 里面的顺序对认证是有影响的。 
ModularRealmAuthenticator 会读取配置在SecurityManager里的Realm。当执行认证是,它会遍历Realm集合,对所有支持提交的token的Realm调用getAuthenticationInfo 。 
因此,如果Realm的顺序对你使用的认证策略结果有影响,那么你应该在配置文件中明确定义Realm的顺序,如: 

blahRealm = com.company.blah.Realm  
...  
fooRealm = com.company.foo.Realm  
...  
barRealm = com.company.another.Realm  
  
securityManager.realms = $fooRealm, $barRealm, $blahRealm

以上就是Apache Shiro 使用手册(二)Shiro 认证的内容,更多相关内容请关注PHP中文网(www.php.cn)!


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn