1. 程式人生 > >shiro身份驗證

shiro身份驗證

hello nds 郵箱 使用 自己 ger logout 如果 art

身份驗證,即在應用中誰能證明他就是他本人。一般提供如他們的身份ID一些標識信息來表明他就是他本人,如提供身份證,用戶名/密碼來證明。

在shiro中,用戶需要提供principals (身份)和credentials(證明)給shiro,從而應用能驗證用戶身份:

principals:身份,即主體的標識屬性,可以是任何東西,如用戶名、郵箱等,唯一即可。一個主體可以有多個principals,但只有一個Primary principals,一般是用戶名/密碼/手機號。

credentials:證明/憑證,即只有主體知道的安全值,如密碼/數字證書等。

最常見的principals和credentials組合就是用戶名/密碼了。

例如在AuthenticationToken 就只提供了兩個方法,分別獲取身份和憑證。AuthenticationToken 的使用的實現一般就是UsernamePasswordToken,但是可以自定義實現,例如JWT token。

public interface AuthenticationToken extends Serializable {

    Object getPrincipal();
    Object getCredentials();

}

對於身份驗證的流程我們同樣可以從外部和內部兩個角度來看

一、外部實現流程

1.、首先準備一些用戶身份/憑據(shiro.ini)

Java代碼
  1. [users]
  2. zhang=123
  3. wang=123

此處使用ini配置文件,通過[users]指定了兩個主體:zhang/123、wang/123。

2、測試用例

@Test  
public void testHelloworld() {  
    //1、獲取SecurityManager工廠,此處使用Ini配置文件初始化SecurityManager  
    Factory<org.apache.shiro.mgt.SecurityManager> factory =  
            new IniSecurityManagerFactory("
classpath:shiro.ini"); //2、得到SecurityManager實例 並綁定給SecurityUtils org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance(); SecurityUtils.setSecurityManager(securityManager); //3、得到Subject及創建用戶名/密碼身份驗證Token(即用戶身份/憑證) Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123"); try { //4、登錄,即身份驗證 subject.login(token); } catch (AuthenticationException e) { //5、身份驗證失敗 } Assert.assertEquals(true, subject.isAuthenticated()); //斷言用戶已經登錄 //6、退出 subject.logout(); }

2.1、首先通過new IniSecurityManagerFactory並指定一個ini配置文件來創建一個SecurityManager工廠;

2.2、接著獲取SecurityManager並綁定到SecurityUtils,這是一個全局設置,設置一次即可;

2.3、通過SecurityUtils得到Subject,其會自動綁定到當前線程;如果在web環境在請求結束時需要解除綁定;然後獲取身份驗證的Token,如用戶名/密碼;

2.4、調用subject.login方法進行登錄,其會自動委托給SecurityManager.login方法進行登錄;

2.5、如果身份驗證失敗請捕獲AuthenticationException或其子類,常見的如: DisabledAccountException(禁用的帳號)、LockedAccountException(鎖定的帳號)、UnknownAccountException(錯誤的帳號)、ExcessiveAttemptsException(登錄失敗次數過多)、IncorrectCredentialsException (錯誤的憑證)、ExpiredCredentialsException(過期的憑證)等,具體請查看其繼承關系;對於頁面的錯誤消息展示,最好使用如“用戶名/密碼錯誤”而不是“用戶名錯誤”/“密碼錯誤”,防止一些惡意用戶非法掃描帳號庫;

2.6、最後可以調用subject.logout退出,其會自動委托給SecurityManager.logout方法退出。

3.Realm實現

org.apache.shiro.realm.Realm接口如下:

String getName(); //返回一個唯一的Realm名字  
boolean supports(AuthenticationToken token); //判斷此Realm是否支持此Token  
AuthenticationInfo getAuthenticationInfo(AuthenticationToken token)  
 throws AuthenticationException;  //根據Token獲取認證信息 

自定義Realm實現:

public class MyRealm1 implements Realm {  
    @Override  
    public String getName() {  
        return "myrealm1";  
    }  
    @Override  
    public boolean supports(AuthenticationToken token) {  
        //僅支持UsernamePasswordToken類型的Token  
        return token instanceof UsernamePasswordToken;   
    }  
    @Override  
    public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {  
        String username = (String)token.getPrincipal();  //得到用戶名  
        String password = new String((char[])token.getCredentials()); //得到密碼  
        if(!"zhang".equals(username)) {  
            throw new UnknownAccountException(); //如果用戶名錯誤  
        }  
        if(!"123".equals(password)) {  
            throw new IncorrectCredentialsException(); //如果密碼錯誤  
        }  
        //如果身份認證驗證成功,返回一個AuthenticationInfo實現;  
        return new SimpleAuthenticationInfo(username, password, getName());  
    }  
}   

二、從內部實現原理來看

技術分享圖片

流程如下:

1、首先調用Subject.login(token)進行登錄,其會自動委托給Security Manager,調用之前必須通過SecurityUtils. setSecurityManager()設置;

2、SecurityManager負責真正的身份驗證邏輯;它會委托給Authenticator進行身份驗證;

3、Authenticator才是真正的身份驗證者,Shiro API中核心的身份認證入口點,此處可以自定義插入自己的實現;

4、Authenticator可能會委托給相應的AuthenticationStrategy進行多Realm身份驗證,默認ModularRealmAuthenticator會調用AuthenticationStrategy進行多Realm身份驗證;

5、Authenticator會把相應的token傳入Realm,從Realm獲取身份驗證信息,如果沒有返回/拋出異常表示身份驗證失敗了。此處可以配置多個Realm,將按照相應的順序及策略進行訪問。

摘自:第二章 身份驗證——《跟我學Shiro》

shiro身份驗證