看源碼,重新審視Spring Security中的角色(roles)是怎麼回事

        在網上看見不少的博客、技術文章,發現大家對於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/course/21185.html ,裏面有詳細的如何進行實戰型的Spring Security角色權限控制模塊的開發。
        重點來了,通過應用角色權限控制的應用,看Spring Security如何利用角色和權限的
四種鑑權的方式:
        hasRole(String role)
        hasAnyRole(String... roles)
        hasAuthority(String authority)
        hasAnyAuthority(String... authorities)
在源碼類SecurityExpressionRoot.java中,我們看看這四種方式的實現形式:
看源碼,重新審視Spring Security中的角色(roles)是怎麼回事
大家從上面的圖看出什麼端倪沒有?
        hasRole(String role) --》 hasAnyRole(String... roles) --》hasAnyAuthorityName
        hasAuthority(String authority) --》hasAnyAuthority(String... authorities) --》hasAnyAuthorityName
不管是基於角色,還是基於權限,最後鑑權都落實到hasAnyAuthorityName這個方法上。

        follow me,我們繼續往下刨根,看看hasAnyAuthorityName這個方法裏面有些什麼,注意上面代碼中的調用hasAnyAuthorityName時,傳遞的參數,一個是
看源碼,重新審視Spring Security中的角色(roles)是怎麼回事
另外一個是
看源碼,重新審視Spring Security中的角色(roles)是怎麼回事
對應的都是一個實現方法。

從hasAnyAuthorityName這個方法中,我們可以知道,這是把傳進去的一個或多個角色/權限,在登錄用戶具有的權限中進行查找
看源碼,重新審視Spring Security中的角色(roles)是怎麼回事
        這裏面的大家看到了吧,角色和權限是混合在一起進行鑑權的(題外話,大家看大神們寫的代碼,注意到其中的var5、var6、var4,這是搞什麼?嚴重不符合命名規範啊)。
那麼Spring Security是如何區分集合中的是權限、還是角色呢,我們繼續抽絲剝繭,看看該方法中的getRoleWithDefaultPrefix(prefix, role)方法
看源碼,重新審視Spring Security中的角色(roles)是怎麼回事
看源碼,重新審視Spring Security中的角色(roles)是怎麼回事
看上面的代碼清晰明瞭了吧,說明如下:
        如果傳進去的角色名稱/權限名稱爲null,直接返回null;
        如果傳進去的角色名稱/權限名稱不爲null,則判斷defaultRolePrefix前綴這個參數是否爲空和其長度,如果不爲空,且長度不爲0,則傳進的參數爲角色名稱,那麼繼續判斷其是否是以“ROLE”開始,如果不是,則在名稱前添加前綴“ROLE”,並返回新的名稱;
        如果不是以上情況,即參數是權限名稱或者帶有“ROLE_”前綴的角色名稱,直接返回傳進去的字符串參數。

        看了以上的部分源碼解析,我們可以得出什麼結論呢(以角色、權限存放在數據庫爲例):
        1、原生的角色和權限並沒有本質的區別,在鑑權時走的是完全相同的一個通道;
        2、在進行權限控制時,角色可加可不加“ROLE”前綴,但在數據庫中定義時,角色名稱一定要添加“ROLE”前綴;
        3、角色與權限之間並沒有建立映射關係,角色是角色、權限是權限,這與我們實際應用中對角色的要求有很大出入;
        4、實際應用中的角色被固化到代碼中,也與實際要求不符,實際應用中,權限作爲子節點可以寫死,而角色作爲全部或者部分權限的集合應該可以靈活調整;
        5、不管是角色鑑權,還是權限鑑權,都只是以角色/權限的名稱作爲判斷依據,所以權限的名稱要唯一。
        另外,從Spring Security的源碼分析中可以發現,我們還可以通過RoleHierarchy進行角色的繼承(默認admin登錄只能訪問/admin,訪問不了/user;而user登錄只能訪問/user),但在實際項目中,最主要強調的是角色的靈活性,而不是繼承性。
        所以,對角色的管理、角色和權限的映射關係,都需要我們自己來實現。
        好了,對Spring Security角色(roles)的分析就到此結束,從以上分析看,我們如果要把Spring Security應用於實際項目中,還需要做不少工作,至於如何簡潔高效的利用Spring Security進行角色權限控制模塊的開發,有興趣的讀者可以看我的視頻介紹:https://edu.51cto.com/course/21185.html ,希望對大家有有所幫助。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章