實戰!Spring Cloud Gateway集成 Rbac 權限模型實現動態權限控制!
這篇文章介紹下網關層如何集成RBAC權限模型進行認證鑒權,文章目錄如下:
什么是RBAC權限模型?
RBAC(Role-Based Access Control)基于角色訪問控制,目前使用最為廣泛的權限模型。
相信大家對這種權限模型已經比較了解了。此模型有三個用戶、角色和權限,在傳統的權限模型用戶直接關聯加了角色層,解耦了用戶和權限,使得權限系統有了更清晰的職責劃分和更高的靈活度。
以上五張表的SQL就不再詳細貼出來了,都會放在案例源碼的doc目錄下,如下圖:
設計思路
RBAC權限模型是基于角色的,因此在Spring Security中的權限就是角色,具體的認證授權流程如下:
- 用戶登錄申請令牌
- 通過UserDetailService查詢、加載用戶信息、比如密碼、權限(角色)....封裝到UserDetails中
- 令牌申請成功,攜帶令牌訪問資源
- 網關層面比較訪問的URL所需要的權限(Redis中)是否與當前令牌具備的權限有交集。有交集則表示具備訪問該URL的權限。
- 具備權限則訪問,否則拒絕
上述只是大致的流程,其中還有一些細節有待商榷,如下:
1、URL對應的權限如何維護?
這個就比較容易實現了,涉及到RBAC權限模式的三張表,分別為權限表、角色表、權限角色對應關系表。具體實現流程如下:
項目啟動時將權限(URL)和角色的對應關系加載到Redis中。
對于管理界面涉及到URL相應關系的變動要實時的變更到Redis。
比如權限中有這么一條數據,如下:
其中的 /order/info 這個URL就是一個權限,管理員可以對其分配給指定的角色。
2、如何實現Restful風格的權限控制?
restful風格的接口URL是相同的,不同的只是請求方式,因此要想做到權限的精細控制還需要保留請求方式,比如POST,GET,PUT,DELETE....
可以在權限表中的url字段放置一個method標識,比如POST,此時的完整URL為:POST:/order/info
當然*:/order/info中的星號表示一切請求方式都滿足。
3、這樣能實現動態權限控制嗎?
權限的控制方式有很多種,比如Security自身的注解、方法攔截,其實擴展Spring Security也是可以實現動態權限控制的,這個在后面的文章中會單獨介紹!
陳某此篇文章是將權限、角色對應關系存入Redis中,因此想要實現動態權限控制只需要在Redis中維護這種關系即可。Redis中的數據如下:
案例實現
此篇文章還是基于以下三個模塊進行改動,有不清楚的可以查看陳某往期文章。
名稱 | 功能 |
---|---|
oauth2-cloud-auth-server | OAuth2.0認證授權服 |
oauth2-cloud-gateway | 網關服務 |
oauth2-cloud-auth-common | 公共模塊 |
涉及到的更改目錄如下圖:
1、從數據庫加載URL<->角色對應關系到Redis
在項目啟動之初直接讀取數據庫中的權限加載到Redis中,當然方法有很多種,自己根據情況選擇。代碼如下:
此處代碼在oauth2-cloud-auth-server模塊下。
案例源碼已經上傳GitHub,關注公眾號:碼猿技術專欄,回復關鍵詞:9529 獲取!
2、實現UserDetailsService加載權限
UserDetailsService相信大家都已經很熟悉了,主要作用就是根據用戶名從數據庫中加載用戶的詳細信息。
代碼如下:
①處的代碼是將通過JPA從數據庫中查詢用戶信息并且組裝角色,必須是以 ROLE_ 開頭。
②處的代碼是將獲取的角色封裝進入authorities向下傳遞。
此處代碼在oauth2-cloud-auth-server模塊下。
案例源碼已經上傳GitHub,關注公眾號:碼猿技術專欄,回復關鍵詞:9529 獲取!
3、鑒權管理器中校驗權限
在上篇文章中實戰干貨!Spring Cloud Gateway 整合 OAuth2.0 實現分布式統一認證授權!詳細介紹了鑒權管理器的作用,這里就不再細說了。代碼如下:
①處的代碼是將請求URL組裝成restful風格的,比如POST:/order/info
②處的代碼是從Redis中取出URL和角色對應關系遍歷,通過AntPathMatcher進行比對,獲取當前請求URL的所需的角色。
③處的代碼就是比較當前URL所需的角色和當前用戶的角色,分為兩步:
如果是超級管理員,則直接放行,不必比較權限
不是超級管理員就需要比較角色,有交集才能放行
此處的代碼在oauth2-cloud-gateway模塊中。
案例源碼已經上傳GitHub,關注公眾號:碼猿技術專欄,回復關鍵詞:9529 獲取!
4、總結
關鍵代碼就是上述三處,另外關于一些DAO層的相關代碼就不再貼出來了,自己下載源碼看看!
案例源碼已經上傳GitHub,關注公眾號:碼猿技術專欄,回復關鍵詞:9529 獲取!
附加的更改
這篇文章中順帶將客戶端信息也放在了數據庫中,前面的文章都是放在內存中。
數據庫中新建一張表,SQL如下:
- CREATE TABLE `oauth_client_details` (
- `client_id` varchar(48) NOT NULL COMMENT '客戶端id',
- `resource_ids` varchar(256) DEFAULT NULL COMMENT '資源的id,多個用逗號分隔',
- `client_secret` varchar(256) DEFAULT NULL COMMENT '客戶端的秘鑰',
- `scope` varchar(256) DEFAULT NULL COMMENT '客戶端的權限,多個用逗號分隔',
- `authorized_grant_types` varchar(256) DEFAULT NULL COMMENT '授權類型,五種,多個用逗號分隔',
- `web_server_redirect_uri` varchar(256) DEFAULT NULL COMMENT '授權碼模式的跳轉uri',
- `authorities` varchar(256) DEFAULT NULL COMMENT '權限,多個用逗號分隔',
- `access_token_validity` int(11) DEFAULT NULL COMMENT 'access_token的過期時間,單位毫秒,覆蓋掉硬編碼',
- `refresh_token_validity` int(11) DEFAULT NULL COMMENT 'refresh_token的過期時間,單位毫秒,覆蓋掉硬編碼',
- `additional_information` varchar(4096) DEFAULT NULL COMMENT '擴展字段,JSON',
- `autoapprove` varchar(256) DEFAULT NULL COMMENT '默認false,是否自動授權',
- PRIMARY KEY (`client_id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
認證服務中的OAuth2.0的配置文件中將客戶端的信息從數據庫中加載,該實現類為JdbcClientDetailsService,關鍵代碼如下:
- @Override
- public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
- //使用JdbcClientDetailsService,從數據庫中加載客戶端的信息
- clients.withClientDetails(new JdbcClientDetailsService(dataSource));
- }
總結
本篇文章介紹了網關集成RBAC權限模型進行認證鑒權,核心思想就是將權限信息加載Redis緩存中,在網關層面的鑒權管理器中進行權限的校驗,其中還整合了Restful風格的URL。