Shiro的身份認證(Authentication)

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

相關文章
相關標籤/搜索