從壹開始 [ Ids4實戰 ] 之五 ║ 多項目集成統一認證中心的思考
- 2019 年 11 月 13 日
- 筆記
前言
哈嘍大家好,好久都沒有寫文章了,這次又重新開始寫技術文章了,半年前我還是一直保持每周都寫文章的,後來是為了響應群友的號召,開始踏上了錄製視頻(https://www.bilibili.com/video/av58096866),直播授課(https://live.bilibili.com/21507364)的道路,目前看來效果還算基本及格吧,雖然人氣沒有那些大佬的多,不過我也是一直很盡心力,包括字幕的錄入,每周三定期的講課,不過真的很累,但是自認為做的還可以了,只是沒能申請上MVP?。
為什麼突然想要寫文章了呢,我是有強迫症的,目前開源了五個系列的文章,從 NetCore 到 Vue,從 Admin 到 Nuxt,然後從 DDD 到 IdentityServer4,我自認為都是貼近實戰的,因為看到某些小夥伴說,應用到了公司的項目里,我也是很開心,而且 NetCore 項目的Github start 數也破千了,我感謝每一個點贊評論的小夥伴,我都是每條評論必回,每個郵件也必回:
我自信這一年多以來,對netcore的基礎知識已經了解的七七八八了,基本都能回答些,但是每當有人問到 IdentityServer4 的相關內容的時候,我都稍微捉襟見肘,雖然我寫了四篇文章,但是因為中間卡了一個心結(具體內容下文會說明),所以沒有進行下去,也讓自己沒有進一步去研究這個框架的動力了,大家肯定都懂那個心理,如果一直有個刺,然後時間長了會刻意迴避它。
不過最後我還是決定要搞起來,既然說到了要佈道,就要走下去,所以我會除了之前的四篇文章外,還再有三到四篇的文章來開啟 Ids4 的第二階段的學習,然後配合還有大概八個視頻的講解,如果你看過我的第一個系列視頻教程,應該心裏有譜,我第二個系列講的怎麼樣,所以我也就不多說了,這兩周準備一下,下周末開啟視頻講解第二系列。
那下面我們就馬上開啟今天的這篇文章吧。
零、回顧與目標
還記得我開啟 IdentityServer4 講解是在半年前,當時我本想是八篇文章,將我的所有項目 —— 主要是 Blog.Admin 和 Blog.Vue 這兩個項目統一集成到 Ids4 的網關授權上來,當然有精力也可以把 DDD 和 Nuxt 的認證也添加進來,只不過 DDD 已經用了 Identity 了,這個優先級可以暫時往後放放,然後就寫了四篇文章,主要是偏重於實戰,而不是講解那老生常談的知識點:
但是在寫到了第四篇文章的時候,出現了一個說小不小,說大不大的問題,讓我擱置了整整半年,是什麼問題,我簡單說說:
我看博客園很多博主在講 Ids4 的時候,基本情況都是用的無狀態的認證方式,什麼意思呢?
1、就是應用場景都是對應的 [Authorize] 這種只要登錄了就可以的項目里,沒有涉及到複雜的策略授權,比如角色和模塊;
2、然後你可能也會說,“ 我看到他們文章講解中生成的 token 中,可以自定義 Role 到 Claim 里呀,你直接在 Blog.Core 項目獲取到 Role 進行策略授權不就行了”,你說的沒錯,但是這裡有一個後續問題;
3、那我的 Role 信息在哪裡管理?是在 Blog.Ids4 (認證服務)項目,還是在 Blog.Core (業務資源服務)項目里?
這裡你可以稍微暫停一下,暫停五分鐘,自己想一想,如何去解決這些問題,特別是第三個問題。
如果你把 Role 的信息管理放到了 Blog.Ids4 項目里,那 Blog.Core 如何針對 Role 進行匹配 Url進行授權配置呢?
但是如果把 Role 管理放到了 Blog.Core 項目里,那就沒有辦法根據 UName 和 Pwd 生成 token 的時候,在 Claims 里生成 Role 信息了。
這個並沒有那麼簡單喲,當然如果你們公司開發過,可以直接看下文,和我想的方案對比下,如果有出入,或者你的更好,我熱烈歡迎提出批評和指導建議,好了,那我就說說我的三種思路把。
一、無狀態的簡單授權認證
這種方案呢,剛剛我們在上文已經說到了,我也已經實現了,就是在文末我的項目中,已經實現這個了, 就是 Blog.Ids4 只單單提供認證功能,不用管 Role 的相關聲明 Claims,基本都是對應的前台項目,比如我們的博客項目和電商項目,用戶登錄了就行,就可以直接發文章或者購買商品了,不用理睬具體啥頁面不能訪問,這個就不多說了,很好理解。
這種場景,很好解決,認證服務項目和資源服務項目 相互獨立,沒有交際,只是提供一個認證網關的作用,這裡就不多說了。
但是這種情況有時候並不是很多,或者說是少數的,我們更多的,還是需要在 token 中攜帶 role 的 claim 聲明,特別是後台管理系統,都是有狀態的授權,比如我們的 Blog.Core 是比較複雜的策略授權,那這個時候就需要討論一下數據庫的問題了,其實重點還是討論 Role 表是在哪個項目維護的問題。
二、有狀態的授權認證中心
那麼問題就來了,我們為了滿足複雜的策略授權,就需要在 Blog.Core 項目里將 Role 和 Url/Api 進行匹配映射到數據庫,那就必須用 Role 表。
但是我們上邊也討論很多了,我們必須要在 token 中攜帶 Role 的Claim,那就必須放到 Blog.Ids4 項目里維護 Role。
這個時候是不是發現兩種情況很矛盾,為了達到這個項目,我簡單看了看 ABP 項目,這個還是群管理 @Kawhi 提的建議,我得到了一絲絲的想法,ABP項目是把認證和資源服務合併到了一起!
1、認證數據庫與業務數據庫合二為一
這個我最終決定採用的方案,具體代碼我已經慢慢的在 Ids4 項目里遷移修改了,感興趣的可以看看,其實說白了,就是把 EFCore 生成表結構的數據庫,指向 Blog.Core 項目的就行了,然後這個時候,我們就看到了兩個 Role 表:
那既然我們的 Ids4 項目用的是 AspNetRoles 來進行認證的,我們直接用這個表不就好了?!,捨棄下邊的 Role 表,用上邊 Ids4 自帶的 AspNetRoles 表,來和我們的 Module 和 Permission 表就行授權映射匹配,這樣是不是完美的解決了我們上邊出現的所有問題!
然後我們的 User 管理和 Role 管理,都移交到了 Ids4 項目里,從而使得我們的 Blog.Coe 資源服務器只需要踏踏實實的做授權就行了:
這個不用擔心看不懂,我在後邊的文章和視頻中也會詳細說到,本文主要說的是這個思路,具體業務邏輯和代碼,我會詳細講解的,你能看懂我的意思就行。
這樣是不是很好的解決了 Role 管理的問題,而且可以快速的將 Blog.Admin 和 Vue 項目給切換過來,很簡單。但是,萬事就怕但是?,這裡有一個問題,就是如果我有多個資源服務器怎麼辦,多個資源服務器肯定是不能和一個認證數據庫合併的,比如我的項目結構是這樣的:
這種我們是不好去把 資源服務器和 認證中心的數據庫放到一起的,當然這種微服務的方案也不是這麼玩兒的,我以後會繼續說到這種情況,如何來設計。
咱們先不說微服務,就說單一服務,那如果不能數據庫合併,又想保證 Role 的良好維護,我想了不是很好的辦法,一共分兩種情況。
2、認證DB與資源DB分離,兩個Role表
既然不放到一起,那就分離開,還是我目前項目 Github 上的情況,兩個數據庫,兩個 Role 表 ,但是呢,對 Role 的管理,還是放到 Ids4 服務器,
只不過這個時候,需要在資源服務器 Blog.Core 里,寫一個定時器或者服務,將 Ids4 Db 中的 AspNetRoles 表數據,統一導入到 Blog.Core Db 的 Roles 表中,然後我們在資源服務器還是來操作 Roles 表,基本我的資源服務器修改的代碼很少,只是多了一個數據同步的方法而已,
相對於上邊的方案,這個優點是:
1、代碼改動小;
2、多個資源服務器可以共存,公用一個認證中心;
3、防止因為 IdentityServer4 官方更新,而破壞我們的資源服務代碼,侵入性小。
缺點也是有的,就是比較 low,而且不能保證實時性,更新速度收到定時器的限制。那和老李討論一下,他給的建議是,可以在不使用表同步,而使用接口的形式,請往下看。
3、認證DB與資源DB分離,一個Role表
這種方案,最終被我 PASS 了,思路我簡單說下,其實很簡單,就是我們的資源服務器 Role 表棄用,整個項目統一用 Ids4 認證服務器提供一個對外暴露的 GetRoles 的 api 接口,來保證實時性和統一性,
但是這樣缺點太明顯,受官網的限制,而且對資源服務器的侵入性太強,儘管可以封裝一個方法。
說這個的目的,只是想讓大家集思廣益,開拓思維,學習都是思考的過程。
三、其他方案
除了我上邊提出來的一些方案,如果你有什麼想法,或者好的注意,可以文章下邊留言或者評論,不勝感激,比如:
1、@老張說:不在資源服務器里進行數據庫的映射匹配,全部寫到Controller控制器的特性上的角色或模塊授權[Authorize(Roles = “Admin,Client”)],這樣也能解決。
2、???
期待你的熱評!
四、Github && Gitee
https://github.com/anjoy8/Blog.IdentityServer