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;
}
}