1. 程式人生 > >Shiro(2)-身份認證

Shiro(2)-身份認證

基本概念

身份驗證
即在應用中誰能證明他就是他本人。一般提供如他們的身份ID 一些標識資訊來表明他就是他本人,如提供身份證,使用者名稱/密碼來證明。在 shiro 中,使用者需要提供principals (身份)和credentials(證明)給shiro,從而應用能驗證使用者身份

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

證明/憑證
即只有主體知道的安全值,如密碼/數字證書等。
最常見的principals和credentials組合就是使用者名稱/密碼了。

認證流程

在這裡插入圖片描述

使用者登陸認證

匯入jar包

<dependency>
	    <groupId>org.apache.shiro</groupId>
	    <artifactId>shiro-core</artifactId>
	    <version>1.3.2</version>
	</dependency>
	<!-- junit -->
	<dependency>
		<groupId>junit</groupId>
		<
artifactId>
junit</artifactId> <version>4.9</version> <scope>test</scope> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency>

配置shiro環境檔案shiro.ini

[users]
root=123
 public static void main(String[] args) {
	//建立SecurityManager工廠,讀取配置檔案
	//注意導包
	Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
	//通過SecurityManager工廠獲取SecurityManager例項
	SecurityManager securityManager = factory.getInstance();
	//將SecurityManager物件設定到環境中
	SecurityUtils.setSecurityManager(securityManager);
	//通過SecurityUtils獲取主體Subject
	Subject subject = SecurityUtils.getSubject();
	//使用者登陸的使用者名稱和密碼,而ini檔案中的使用者名稱和密碼相當資料庫中的user
	UsernamePasswordToken token = new UsernamePasswordToken("root", "123");
	try {
	    //進行使用者身份驗證,如果驗證失敗則丟擲異常
	    subject.login(token);
	    //判斷使用者是否通過驗證
	    if (subject.isAuthenticated()) {
		    System.out.println("登陸成功");
		}
	} catch (AuthenticationException e) {
	    e.printStackTrace();
	    System.out.println("使用者登陸失敗");
	}
    }

自定義Realm

Shiro預設使用自帶的IniRealm,IniRealm從ini配置檔案中讀取使用者的資訊,大部分情況下需要從系統的資料庫中讀取使用者資訊,所以需要自定義realm。

在這裡插入圖片描述
最基礎的是Realm介面,CachingRealm負責快取處理,AuthenticationRealm負責認證,AuthorizingRealm負責授權,通常自定義的realm繼承AuthorizingRealm

自定義Realm實現

public class UserRealm extends AuthorizingRealm {
    
    public String getName(){
	return "userRealm";
    }
    
    
    /**
     * @Description:獲取許可權資訊
     * @param principals
     * @return
     */
    protected AuthorizationInfo doGetAuthorizationInfo(
	    PrincipalCollection principals) {
	
	return null;
    }

    
    /**
     * @Description:完成身份認證
     * @param token
     * @return
     * @throws AuthenticationException
     */
    protected AuthenticationInfo doGetAuthenticationInfo(
	    AuthenticationToken token) throws AuthenticationException {
	//獲取使用者輸入的使用者名稱
	String username = (String) token.getPrincipal();
	System.out.println("第一個Realm:");
	System.out.println("username===="+username);
	//根據使用者名稱查詢資料庫獲取密碼
	String password = "123";
	//將從資料庫中獲取的資訊封裝到
	SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username,password,getName());
	return info;
    }
}

要想使用自定義的realm需要先在shiro.ini中配置Realm,類似於spring的依賴注入

[main]
#自定義 realm
userRealm=com.QEcode.realm.UserRealm
#將realm設定到securityManager
securityManager.realms=$userRealm

Authenticator

Authenticator 的職責是驗證使用者帳號,是 Shiro API 中身份驗證核心的入口點.
在這裡插入圖片描述

如果驗證成功,將返回 AuthenticationInfo 驗證資訊;此資訊中包含了身份及憑證;如果驗證失敗將丟擲相應的 AuthenticationException 實現。

SecurityManager 介面繼承了 Authenticator,另外還有一個 ModularRealmAuthenticator 實現,其委託給多個 Realm 進行驗證,驗證規則通過 AuthenticationStrategy 介面指定,預設提供的實現:
FirstSuccessfulStrategy:只要有一個 Realm 驗證成功即可,只返回第一個 Realm 身份驗證成功的認證資訊,其他的忽略;
AtLeastOneSuccessfulStrategy:只要有一個 Realm 驗證成功即可,和 FirstSuccessfulStrategy不同,返回所有 Realm 身份驗證成功的認證資訊;
AllSuccessfulStrategy所有 Realm 驗證成功才算成功,且返回所有 Realm 身份驗證成功的認證資訊,如果有一個失敗就失敗了。
ModularRealmAuthenticator 預設使AtLeastOneSuccessfulStrategy 策略。

在ini 配置檔案中指定

[main]
userRealm = com.QEcode.realm.UserRealm
userRealm2 = com.QEcode.realm.UserRealm2

# 配置驗證器
authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator
# 指定驗證規則為AllSuccessfulStrategy 所有 Realm 驗證成功才算成功,
allSuccessfulStrategy=org.apache.shiro.authc.pam.AllSuccessfulStrategy

# 指定驗證規則為AtLeastOneSuccessfulStrategy 只要有一個 Realm 驗證成功返回所有 Realm 身份驗證成功的認證資訊
atLeastOneSuccessfulStrategy = org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy

# 指定驗證規則為FirstSuccessfulStrategy 只要有一個 Realm 驗證成功即可,只返回第一個 Realm 身份驗證成功的認證資訊
firstSuccessfulStrategy = org.apache.shiro.authc.pam.FirstSuccessfulStrategy

#指定 securityManager 的 authenticator 實現
authenticator.authenticationStrategy=$firstSuccessfulStrategy

securityManager.authenticator=$authenticator

securityManager.realms=$userRealm , $userRealm2

public class UserRealm2 extends AuthorizingRealm {
    
    public String getName(){
	return "userRealm2";
    }
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(
	    PrincipalCollection principals) {
	// TODO 自動生成的方法存根
	return null;
    }

    /**
     * @Description:身份認證
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
	    AuthenticationToken token) throws AuthenticationException {
	// 獲取使用者輸入的使用者名稱
	String username = (String) token.getPrincipal();
	System.out.println("第二個Realm:");
	System.out.println("username====" + username);
	// 根據使用者名稱查詢資料庫獲取密碼
	String password = "123";
	// 將從資料庫中獲取的資訊封裝到
	SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username,
		password, getName());
	return null;
    }
}