博主是一個剛步入北漂的低級碼農,具體就不多說了,開車。
能知道shiro,看到此篇文章的,估計絕大多數都是像我一樣被老大安排開發權限那一塊的功能的搬磚萌新。
google、百度了半天,看了大量shiro的入門教程。隨後帶着一臉懵逼...
開發環境是spring全家桶系列還好,如果像我一樣,開發環境完全是其他底層(我們是netty)的,基本上就GG了。
畢竟我只需要shiro的後臺的某一些功能,沒必要用那些花裏胡哨的= =。
故而,本篇博文的編輯,其實就爲了給GG的同行,行一個不算方便的方便。
需要的東西:
JDK(我用的是通用的1.8)
一個依賴管理工具(我用的是gradle)
ide(我的是idea)
--------------華麗的分割線--------------------
依賴速成的話就一個,權限的開發足夠用了
gradle:
compile group: 'org.apache.shiro', name: 'shiro-core', version: '1.4.0'
Maven:
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
版本的話用的是不新不舊的,想要自己找去這個網站搜索:https://mvnrepository.com/ 這個網站是後臺媛與猿的神器,不解釋。
---------分割線-----------
依賴弄好了之後,我們首先弄清楚的是三個東西。
Realm、SecurityManager、Subject 這三個是shiro在後臺的絕對的核心。
Realm實際上就是存儲着權限、角色的DB對象,SecurityManager則是管理者,Subject 則是對應的用戶
(1)Realm:
Realm是一個接口,需要我們去實現,而shiro自帶了一些實現Realm的基礎class,爲了更加適用絕大多數人,我們就略過了。
首先,我們先看如下這個實現邏輯
public class DatabaseRealm extends AuthorizingRealm {
/**
* 獲取賬號的角色、資源
*
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//能進入到這裏,表示賬號已經通過驗證了
String userName = (String) principalCollection.getPrimaryPrincipal();
//根據userName獲取該賬戶擁有的角色(這個邏輯自己用自己的數據庫搞定)
Set<String> setRoles = getRolesByUserName(userName);
//根據角色獲取該賬戶擁有的資源(這個也是,自己用自己的數據庫搞定)
Set<String> setPermissions = getPermissionsByRoles(setRoles);
//授權對象
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//把獲取到的角色和資源放進去
info.setStringPermissions(setPermissions);
info.setRoles(setRoles);
return info;
}
/**
* 根據token驗證賬戶登錄
*
* @param token
* @return 認證信息
* @throws AuthenticationException 如果登錄失敗,拋出這個錯誤
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//根據token獲取認證的賬號密碼
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
String userName = token.getPrincipal().toString();
String password = new String(usernamePasswordToken.getPassword());
//判斷數據庫中是存在該用戶(這個邏輯自己從數據庫中拿出來)
//(這個也自己搞定)
if (賬號不存在) {
throw new AuthenticationException();
}
//認證信息裏存放賬號密碼, getName() 是當前Realm的繼承方法,通常返回當前類名 :databaseRealm
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(userName, password, getName());
return info;
}
}
如上,我們一定要繼承AuthorizingRealm ,達到實現Realm的目的,確保Realm能夠根據username和password
從自己項目的數據庫中拿出想要的角色、資源(權限)數據,中間自己實現的過程,就看各位項目中的數據庫了。
(2)SecurityManager:
Realm實現後,我們有了通過自己的數據庫獲得權限,角色的對象,那麼,就需要將對象給予
SecurityManager統一管理,再此看如下代碼:
public class SecurityManager {
//初始化管理者(用它管控所有的權限判定)
public static final SecurityManager securityManager = SecurityManager.VOID();
//new一個對象 ^_^
public static SecurityManager VOID() {
return new SecurityManager();
}
private SecurityManager() {
//初始化
init();
}
//初始化
private void init() {
//初始化管理者
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
//將數據庫實現類綁定到管理者
defaultSecurityManager.setRealm(new DatabaseRealm());
//將 SecurityManager 實例綁定給 SecurityUtils
SecurityUtils.setSecurityManager(defaultSecurityManager);
}
//獲取當前線程主題
private Subject getSubject() {
return SecurityUtils.getSubject();
}
//獲取登錄用的token
private UsernamePasswordToken getToken(String userName, String password) {
return new UsernamePasswordToken(userName, password);
}
//傳入用戶id,返回用戶的Subject
private Subject getSubject(String username,String password) {
//獲取主題
Subject subject = getSubject();
//認證登錄
try {
subject.login(getToken(username,password));
} catch (AuthenticationException e) {
sout回車("用戶驗證身份時出現異常:" + e);
}
return subject;
}
//外部通用方法-判斷用戶是否爲某個角色
public boolean isRole(String username,String password, String role) {
//獲取用戶身份subject
Subject subject = getSubject(username,password);
//判斷角色
boolean isRole = subject.hasRole(role);
//登出
subject.logout();
return isRole;
}
//外部通用方法-判斷用戶是否擁有某個資源
public boolean isPermitted(String username,String password, String permission) {
//獲取用戶身份subject
Subject subject = getSubject(username,password);
//判斷是否擁有資源
boolean isPermitted = subject.isPermitted(permission);
//登出
subject.logout();
return isPermitted;
}
}
咳咳 = =代碼幾乎都是手打的,可能有些錯誤,項目中引用的其他東西太多了,湊合着看。
其中 init()方法中的邏輯就是講Realm的實現給予SecurityManager統一管理的初始化邏輯
(3)Subject :
一個subject對應一個用戶(什麼張三啊,李四啊)
剛纔的代碼中另外貼了Subject的應用,其中重要的有:
獲取subject:SecurityUtils.getSubject();
//(獲取subject是自帶多線程的,不過一個線程只能有一個,切記,單線程的話多次獲取,後一個會覆蓋前一個)
登錄認證:subject.login()
取消登錄:subject.logout()
判斷用戶是否擁有角色: subject.hasRole(role);
判斷用戶是否擁有資源(權限):subject.isPermitted;
這些方法足夠一個小中型項目完成後臺的所有權限邏輯判斷了,足夠了,具體的詳情網上一大堆,我就不多說了。
本章主要的精髓就是上面這兩頁代碼,剩下的就是基於項目的業務代碼了,shiro入門時候如果遇到瓶頸,本文絕對
會讓你有所收穫的。
----------------------------------------------
本人實在是太懶了= =就不多打了,框架這東西重在嘗試,我只是提供一個思路~