上一次,使用spring security
與angular
實現了使用者認證。spring security and angular 實現使用者認證
本次,我們通過spring security
的授權機制,實現使用者授權。
實現十分簡單,大家認真聽,都能聽得懂。
前台實現了選單的許可權控制,但後台介面還沒進行保護,只要使用者登入成功,什麼介面都可以呼叫。
我們希望實現:使用者有什麼選單的許可權,只能訪問後台對應該選單的介面。
比如,使用者有計算機組管理的選單,就可以訪問計算機組相關的增刪改查介面,但是其他的介面都不允許訪問。
依據spring security
的設計,使用者對應角色,角色對應後台介面。這是沒什麼問題的。
示例
某介面新增@secured
註解,內部新增許可權表示式。
@secured("role_admin")
public listgetall()
然後再為使用者建立spring security
中的角色。
這裡我們為使用者新增role_admin
的角色授權,與getall
方法上的@secured("role_admin")
註解中的引數一致,表示該使用者有許可權訪問該方法,這就是授權。
private userdetails createuser(user user)
作為一款優秀的安全框架而言,spring security
這樣設計是沒有任何問題的,我們只需要簡簡單單的幾行**就能實現介面的授權管理。
但是卻不符合我們的要求。
我們要求,在我們的系統中,使用者對應多角色。
但是我們的角色是要求可以進行動態配置的,今天有乙個系統管理員的角色,明天可能又加乙個教師的角色。
在使用者授權這方面,是可以實現動態配置的,因為使用者的許可權列表是乙個list
,我可以從資料庫查當前使用者的角色,然後add
進去。
private userdetails createuser(user user)
但是在介面級別,就無法實現動態配置了。大家想想,註解裡,要求的引數必須是常量,就是我們想動態配置,也實現不了啊?
@secured("role_admin")
public listgetall()
所以,我們總結,因為註解配置的限制,所以在spring security
中角色是靜態的。
我們的角色是動態的,而spring security
中的角色是靜態的,所以不能將我們的角色直接對映到spring security
中的角色,要對映也得拿乙個我們系統中靜態的物件與之對應。
角色是動態的,這個不行了。但是我們的選單是靜態的啊。
功能模組是我們開發的,選單就這麼固定的幾個,使用者管理、角色管理、系統設定啥的,在我們開發期間就已經固定下來了,我們是不是可以使用選單結合spring security
進行授權呢?
認真看這張圖,看懂了這張圖,你應該就明白了我的設計思想。
角色是動態的,我不用它授權,我使用靜態的選單進行授權。
靜態的選單對應spring security
中靜態的角色,角色再對應後台介面,如此設計,就實現了我們的設想:使用者擁有哪個選單的許可權,就只擁有被該選單呼叫的相應介面許可權。
設計好了,一起來寫**吧。
spring security
中有多種授權註解,個人經過對比之後選擇@secured
註解,因為我覺得這個註解配置項更容易被人理解。
public @inte***ce secured
直接寫乙個角色的字串陣列傳進去即可。
@secured("role_admin") // 需要擁有`role_admin`角色才可訪問
@secured() // 使用者擁有`role_admin`、`role_teacher`二者之一即可訪問
注意:這裡的字串一定是以role_
開頭,spring security
才把它當成角色的配置,否則無效。預設的spring security
是不進行授權註解攔截的,新增註解@enableglobalmethodsecurity
以啟用@secured
註解的全域性方法攔截。
@enableglobalmethodsecurity(securedenabled = true) // 啟用全域性方法安全,採用@secured方式
在選單中新建乙個字段securityrolename
來宣告我們的系統選單對應著哪個spring security
角色。
// 該選單在spring security環境下的角色名稱
@column(nullable = false)
private string securityrolename;
建乙個類,用於存放所有spring security
角色的配置資訊,供全域性呼叫。
這裡不能用列舉,@secured
註解中要求必須是string
陣列,如果是列舉,需要通過yunzhisecurityroleenum.role_main.name()
格式獲取字串資訊,但很遺憾,註解中要求必須是常量。
還記得上次自定義http
狀態碼的時候,吃了列舉類無法擴充套件的虧,以後再也不用列舉了。就算用列舉,也會設計乙個介面,列舉實現該介面,不用列舉宣告方法的引數型別,而使用介面宣告,方便擴充套件。
package club.yunzhi.huasoft.security;
/** * @author zhangxishuo on 2019-03-02
* yunzhi security 角色
* 該角色對應選單
*/public class yunzhisecurityrole
示例@secured()
public listgetall()
**體現授權思路:遍歷當前使用者的選單,根據選單中對應的security
角色名進行授權。
private userdetails createuser(user user)
logger.debug("構建使用者");
return new org.springframework.security.core.userdetails.user(user.getusername(), user.getpassword(), authorities);
}
注:這裡遇到了hibernate
惰性載入引起的錯誤,啟用事務防止hibernate
關閉session
,深層原理目前還在研究。單元測試很簡單,供寫相同功能的人參考。
@test
public void authtest() throws exception
private string loginwithusernameandpassword(string username, string password) throws exception
感謝開源社群,感謝spring security
。五行**(不算注釋),乙個註解。就解決了一直以來困擾我們的許可權問題。
初步理解Spring Security並實踐
spring security如何使用,先在你的專案pom.xml檔案中宣告依賴。org.springframework.bootgroupid spring boot starter securityartifactid dependency 然後建立乙個類並繼承websecurityconfig...
初步理解Spring Security並實踐
spring security如何使用,先在你的專案pom.xml檔案中宣告依賴。org.springframework.boot spring boot starter security 然後建立乙個類並繼承websecurityconfigureradapter這個方法,並在之類中重寫confi...
初步理解Spring Security並實踐
spring security如何使用,先在你的專案pom.xml檔案中宣告依賴。org.springframework.boot spring boot starter security 然後建立乙個類並繼承websecurityconfigureradapter這個方法,並在之類中重寫confi...