一、認證的流程
- 獲取當前的Subject, 調用
SecurityUtils.getSubject()
; - 測試當前用戶是否已經被認證, 即是否已經登錄, 調用Subject的
isAuthentication()
- 若沒有被認證, 則把用戶名和密碼封裝爲
UsernamePasswordToken
對象- 創建一個表單頁面
- 把請求提交到Controller中
- 獲取用戶名和密碼
- 前臺執行登錄, 調用Subject的
login(AuthenticationToken)
方法 - 自定義Realm, 從數據庫中獲取對應的記錄, 返回給Shiro
- 自定義的Realm需要繼承
org.apache.shiro.realm.AuthorizingRealm
類 - 實現
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
方法 - 實現方法中的參數就是前臺中login方法中的token
- 自定義的Realm需要繼承
- 由shiro內部自動完成密碼的比對
二、認證實現
Controller
實現doGetAuthenticationInfo方法
// 認證
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("執行了->認證UserRealm.doGetAuthenticationInfo");
// 1. 把AuthenticationToken 轉爲 UsernamePasswordToken
UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;
// 2. 從數據庫中獲取用戶: userToken.getUsername()就是前臺用戶輸入的用戶名
User user = userService.queryUserByName(userToken.getUsername());
// 3. 用戶不存在, 拋出異常
if (user == null) {
return null; // 拋出異常 UnknowAccountException
}
// 4. 根據用戶的情況,來構建 AuthenticationInfo對象並返回,常常使用SimpleAuthenticationInfo
// arg1: principal: 認證的實體信息,可以是username,也可以是數據表中對應用戶的實體類
// arg2: credentials: 密碼,shiro底層自動幫我們做比對了
// arg3: realName: 當前realm對象的name, 調用父類的getName()即可
return new SimpleAuthenticationInfo(user, user.getPwd(), "");
}
- 在Controller中封裝的token(封裝了用戶的信息), 爲什麼和我們重寫的
doGetAuthenticationInfo
方法參數是同一個對象;
首先從Controller中subject.login(token)
的login方法點進去一直找(如下圖)
找到AuthenticatingRealm
類中的方法, 其中就調用了我們重寫的doGetAuthenticationInfo(token)
方法, 即將用戶封裝的信息傳遞了過去!
三、shiro鹽值加密md5
四、授權
授權流程
- 自定義的Realm繼承
AuthorizingRealm
類實現protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection)
方法