Authentication概述html
n概述java
Authentication 是指身份驗證的過程——即證實一個用戶其實是不是他們所說的他們是誰。也就是說經過提交用戶的身份和憑證給Shiro,以判斷它們是否和應用程序預期的相匹配。數據庫
n基本概念apache
1:Principals(身份):是Subject 的‘identifying attributes(標識屬性)’。好比咱們登陸提交的用戶名。安全
2:Credentials(憑證):一般是隻被Subject 知道的祕密值,它用來做爲一種起支持做用的證據,此證據事實上包含着所謂的身份證實。好比咱們登陸提供的密碼cookie
n認證的基本步驟session
1. 收集Subjects 提交的Principals(身份)和Credentials(憑證);ide
2. 提交Principals(身份)和Credentials(憑證)進行身份驗證;code
3. 若是提交成功,則容許訪問,不然從新進行身份驗證或者阻止訪問。htm
認證樣例
n使用用戶名/密碼的樣例
UsernamePasswordToken token = new UsernamePasswordToken(username, password); token.setRememberMe(true);
樣例使用UsernamePasswordToken 來支持最多見的用戶名/密碼的身份驗證方法。這是Shiro的org.apache.shiro.authc.AuthenticationToken 的接口,是Shiro 表明提交的Principals(身份)和Credentials(憑證)的身份驗證系統所使用的基本接口的一個實現。
n提交用戶名/密碼進行認證
Subject currentUser = SecurityUtils.getSubject(); currentUser.login(token);
n處理認證成功和失敗
若是認證成功,會沒有返回,也沒有例外,經過。
若是認證失敗,會拋出例外,你能夠在程序中捕獲並處理,以下示例:
try { currentUser.login(token); } catch ( UnknownAccountException uae ) { … } catch ( IncorrectCredentialsException ice ) { … } catch (LockedAccountException lae ) { … } catch (ExcessiveAttemptsException eae ) { … } … catch your own … nlogout(註銷) currentUser.logout();
當你調用logout,任何現有的Session 都將會失效,並且任何身份都將會失去關聯(例如,在Web 應用程序中,RememberMe cookie 也將被刪除)。在Subject 註銷後,該Subject的實例被再次認爲是匿名的,固然,除了Web 應用程序。
注意:因爲在Web 應用程序記住身份每每是依靠Cookies,然而Cookies 只能在Response 被committed 以前被刪除,因此強烈建議在調用subject.logout()後當即將終端用戶重定向到一個新的視圖或頁面。
這樣可以保證任何與安全相關的Cookies 都能像預期的同樣被刪除。這是HTTP cookies 的功能限制,而不是Shiro的。
Remembered和Authenticated
nRemembered(記住我)
一個記住個人Subject 不是匿名的,是有一個已知的身份ID(也就是subject.getPrincipals()是非空的)。可是這個被記住的身份ID 是在以前的session 中被認證的。若是subject.isRemembered()返回true,則Subject 被認爲是被記住的。
nAuthenticated(已認證)
一個已認證的Subject 是指在當前Session 中被成功地驗證過了(也就是說,login方法被調用而且沒有拋出異常)。若是subject.isAuthenticated()返回true 則認爲Subject 已經過驗證。
n注意他們是互斥的
Remembered 和Authenticated 是互斥的——若其中一個爲真則另外一個爲假,反之亦然
認證順序
nStep 1:應用程序代碼調用Subject.login 方法,傳遞建立好的包含終端用戶的Principals(身份)和Credentials(憑證)的AuthenticationToken 實例。
nStep 2:Subject實例,一般是DelegatingSubject(或子類)委託應用程序的SecurityManager經過調用securityManager.login(token)開始真正的驗證。
nStep3:SubjectManager 接收token 以及簡單地委託給內部的Authenticator 實例經過調用authenticator.authenticate(token)。這一般是一個ModularRealmAuthenticator 實例,支持在身份驗證中協調一個或多個Realm 實例。
n
nStep 4:若是應用程序中配置了一個以上的Realm,ModularRealmAuthenticator 實例將利用配置好的AuthenticationStrategy 來啓動Multi-Realm 認證嘗試。在Realms 被身份驗證調用以前,期間和之後,AuthenticationStrategy 被調用使其可以對每一個Realm 的結果做出反應。
n
nStep 5:每一個配置的Realm 用來幫助看它是否支持提交的AuthenticationToken。若是支持,那麼支持Realm 的getAuthenticationInfo 方法將會伴隨着提交的token 被調用。getAuthenticationInfo 方法有效地表明一個特定Realm 的單一的身份驗證嘗試。
初識自定義 Realm
n這裏先來個例子,認識一下:
public class MyRealm extends AuthorizingRealm{ protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String userName = (String) getAvailablePrincipal(principals); //經過用戶名去得到用戶的全部資源,並把資源存入info中 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); Set<String> s = new HashSet<String>(); s.add("p1"); s.add("p2"); info.setStringPermissions(s); Set<String> r = new HashSet<String>(); r.add("r1"); r.add("r2"); info.setRoles(r); return info;} protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken token) throws AuthenticationException { //token中儲存着輸入的用戶名和密碼 UsernamePasswordToken upToken = (UsernamePasswordToken)token; String username = upToken.getUsername(); String password = String.valueOf(upToken.getPassword()); //一般是與數據庫中用戶名和密碼進行比對,這裏就省略了 //比對成功則返回info,比對失敗則拋出對應信息的異常AuthenticationException SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password .toCharArray(),getName()); return info; }}
配置多個Realm
n上面的例子能夠做爲第一個Realm
n再複製一份,定義爲MyRealm2,在返回user前添加拋出一個例外,表示認真沒有經過,以下:
if(username.equals("javass")){ throw new AuthenticationException("MyRealm2 認證失敗"); } SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password .toCharArray(),getName()); // n在配置文件裏面添加Realm的定義 myRealm1=cn.javass.hello.MyRealm myRealm2=cn.javass.hello.MyRealm2
因爲有多個realm,通常就須要配置AuthenticationStrategy了,而AuthenticationStrategy是跟Authenticator(認證器)相關的。
n配置Authenticator和AuthenticationStrategy
authenticator = org.apache.shiro.authc.pam.ModularRealmAuthenticator authcStrategy = org.apache.shiro.authc.pam.AllSuccessfulStrategy authenticator.authenticationStrategy = $authcStrategy authenticator.realms=$myRealm2,$myRealm1
n固然,你能夠擴展並實現本身的Authenticator,通常沒有必要
n最後把Authenticator設置給securityManager
securityManager.authenticator = $authenticator
n關於AuthenticationStrategy的配置,有三種:
AtLeastOneSuccessfulStrategy :若是一個(或更多)Realm 驗證成功,則總體的嘗試被認爲是成功的。若是沒有一個驗證成功,則總體嘗試失敗。
FirstSuccessfulStrategy 只有第一個成功地驗證的Realm 返回的信息將被使用。全部進一步的Realm 將被忽略。若是沒有一個驗證成功,則總體嘗試失敗
AllSucessfulStrategy 爲了總體的嘗試成功,全部配置的Realm 必須驗證成功。若是沒有一個驗證成功,則總體嘗試失敗。
ModularRealmAuthenticator 默認的是AtLeastOneSuccessfulStrategy
n自定義本身的AuthenticationStrategy,一般是擴展自AbstractAuthenticationStrategy,示例以下:
public class MyAuthenticationStrategy extends AbstractAuthenticationStrategy{ public AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo singleRealmInfo, AuthenticationInfo aggregateInfo, Throwable t) throws AuthenticationException { if(realm.getName().equals("myRealm2")){ if(singleRealmInfo==null || singleRealmInfo.getPrincipals()==null){ throw new AuthenticationException("主戰認證未經過"); } } return super.afterAttempt(realm, token, singleRealmInfo, aggregateInfo, t); } }
至於具體覆蓋擴展什麼方法,須要根據你具體的策略來定。
多個Realm的驗證順序
n概述
很是重要的一點是:ModularRealmAuthenticator 將與Realm 實例以迭代的順序進行交互。
在SecurityManager 中已經配置好了ModularRealmAuthenticator 對Realm實例的訪問。當執行一個認證嘗試時,它將會遍歷該集合,並對每個支持提交AuthenticationToken 的Realm 調用Realm 的getAuthenticationInfo 方法
n隱式排列
當你配置多個realm的時候,處理的順序默認就是你配置的順序。
這種狀況一般就是隻定義了realm,而沒有配置securityManager的realms
n顯示排列
也就是顯示的配置securityManager.realms,那麼執行的順序就是你配置該值的realm的順序。
一般更推薦顯示排列。
私塾在線原創,轉載請註明http://sishuok.com/forum/blogPost/list/0/7455.html