在網上看見很多的博客、技術文章,發現你們對於Spring Security中的角色(roles)存在較大的誤解,最大的誤解就是沒有搞清楚其中角色和權限的差異(好多人在學習Spring Security時,是否是對於到底加不加「ROLE_」前綴有點犯蒙),有時候以爲在進行權限控制時用權限名稱或者用角色名稱都差很少(你們這種感受是對的,若是簡單應用確實差不太多)。
咱們在進行角色權限控制設計時,通常包括帳戶(users)、角色(roles)、權限(authorities)這三部分。
1)一個帳戶通常對應一個或多個角色;
2)一個角色對應多個權限(authorities),反過來一個權限也對應多個角色;
3)帳戶只和角色關聯,經過角色,間接和權限產生關係;
4)角色不是固定死的,是可以動態建立的,每一個角色具備的權限可以靈活的進行調整;
5)在系統完成詳細設計後,有哪些權限就已經肯定下來,權限的層級結構和數量、與帳戶和角色沒半點關係。
基於以上的說明,咱們從源碼的角度來講明Spring Security的帳戶、角色和權限是怎麼一回事。
Spring Security工做流程:經過登陸的帳戶,找到該帳戶對應的角色/權限,並把自定義的權限集合轉換爲Spring Security承認的權限集合List<GrantedAuthority>,而後結合自定義的帳號、密碼,和新權限集合這三個參數,建立一個Spring Security承認的帳號實例,再而後根據自定義的鑑權規則,進行權限控制。
這裏面如何建立帳號、角色、權限,實現用戶認證、進行鑑權的細節就不講了,由於這個不是本篇文章的重點,有興趣的讀者能夠看個人視頻介紹:https://edu.51cto.com/sd/091c7 ,裏面有詳細的如何進行實戰型的Spring Security角色權限控制模塊的開發。
重點來了,經過應用角色權限控制的應用,看Spring Security如何利用角色和權限的
四種鑑權的方式:
hasRole(String role)
hasAnyRole(String... roles)
hasAuthority(String authority)
hasAnyAuthority(String... authorities)
在源碼類SecurityExpressionRoot.java中,咱們看看這四種方式的實現形式:
你們從上面的圖看出什麼端倪沒有?
hasRole(String role) --》 hasAnyRole(String... roles) --》hasAnyAuthorityName
hasAuthority(String authority) --》hasAnyAuthority(String... authorities) --》hasAnyAuthorityName
不論是基於角色,仍是基於權限,最後鑑權都落實到hasAnyAuthorityName這個方法上。 java
follow me,咱們繼續往下刨根,看看hasAnyAuthorityName這個方法裏面有些什麼,注意上面代碼中的調用hasAnyAuthorityName時,傳遞的參數,一個是
另一個是
對應的都是一個實現方法。 數據庫
從hasAnyAuthorityName這個方法中,咱們能夠知道,這是把傳進去的一個或多個角色/權限,在登陸用戶具備的權限中進行查找
這裏面的你們看到了吧,角色和權限是混合在一塊兒進行鑑權的(題外話,你們看大神們寫的代碼,注意到其中的var五、var六、var4,這是搞什麼?嚴重不符合命名規範啊)。
那麼Spring Security是如何區分集合中的是權限、仍是角色呢,咱們繼續抽絲剝繭,看看該方法中的getRoleWithDefaultPrefix(prefix, role)方法
看上面的代碼清晰明瞭了吧,說明以下:
若是傳進去的角色名稱/權限名稱爲null,直接返回null;
若是傳進去的角色名稱/權限名稱不爲null,則判斷defaultRolePrefix前綴這個參數是否爲空和其長度,若是不爲空,且長度不爲0,則傳進的參數爲角色名稱,那麼繼續判斷其是不是以「ROLE」開始,若是不是,則在名稱前添加前綴「ROLE」,並返回新的名稱;
若是不是以上狀況,即參數是權限名稱或者帶有「ROLE_」前綴的角色名稱,直接返回傳進去的字符串參數。ide
看了以上Spring Security的部分源碼解析,咱們能夠得出什麼結論呢(以角色、權限存放在數據庫爲例):
一、原生的角色和權限並無本質的區別,在鑑權時走的是徹底相同的一個通道;
二、在進行權限控制時,角色可加可不加「ROLE」前綴,但在數據庫中定義時,角色名稱必定要添加「ROLE」前綴;
三、角色與權限之間並無創建映射關係,角色是角色、權限是權限,這與咱們實際應用中對角色的要求有很大出入;
四、實際應用中的角色被固化到代碼中,也與實際要求不符,實際應用中,權限做爲子節點能夠寫死,而角色做爲所有或者部分權限的集合應該能夠靈活調整;
五、不論是角色鑑權,仍是權限鑑權,都只是以角色/權限的名稱做爲判斷依據,因此權限的名稱要惟一。
另外,從Spring Security的源碼分析中能夠發現,咱們還能夠經過RoleHierarchy進行角色的繼承(默認admin登陸只能訪問/admin,訪問不了/user;而user登陸只能訪問/user),但在實際項目中,最主要強調的是角色的靈活性,而不是繼承性。
因此,對角色的管理、角色和權限的映射關係,都須要咱們本身來實現。
好了,對Spring Security角色(roles)的分析就到此結束,從以上分析看,咱們若是要把Spring Security應用於實際項目中,還須要作很多工做,至於如何簡潔高效的利用Spring Security進行角色權限控制模塊的開發,有興趣的讀者能夠看個人視頻介紹:https://edu.51cto.com/sd/091c7 ,但願對你們有有所幫助。源碼分析