从壹开始 [ Ids4实战 ] 之三║ 详解授权持久化 用户数据迁移
哈嘍大家周三好,今天終于又重新開啟 IdentityServer4 的落地教程了,不多說,既然開始了,就要努力做好?。
書接上文,在很久之前的上篇文章《二║ 基礎知識集合 & 項目搭建一》中,我們簡單的說了說 IdentityServer4 是如何調用和配置 Token 的,主要是一些入門的基礎知識和概念,也算是第一次嘗鮮了,其實 Ids4 本身沒有那么神秘,我們只需要知道它是一個豐富的認證框架,又具有很好的可擴展性,核心就是如何配置某些客戶端通過該授權服務來包括另一些資源服務器,供用戶使用。因為中間隔了很長時間了,這里簡單的回顧下上篇文章說了什么,下邊這幾個小問題,相信大家腦中都能很快的有一些概念,至少是臉熟了,如果不是很清楚,請翻看上邊的鏈接,或者官網再看看:
1、什么是資源?什么是客戶端?什么是令牌 ?
2、IdentityServer4 主要是授權還是認證 ?
3、OAuth 2.0、OpenID、OpenID Connect三者的關系 ?
4、Ids4 依賴的 Nuget 包是什么 ?
5、如何快速開發 UI ?
?今天這篇文章主要是操作和探索相結合的一篇,我看網上很多教程,基本上是按照官網概念的知識點,配合著 Github 開源地址,講解一遍,知識是懂了,可是要是自己開發起來,還是有很多的疑惑,甚至是根本走不下去,我就從初學者的立場出發,換一個思路,簡單的對其進行探索,希望能讓初學者感興趣,而不會失去學習的沖動,當然,這篇文章不會一下子就很完整,需要一段時間的沉淀和完善,我會不定時將學習到的感悟一一補充下來,然后也會和別人討論的心得寫下來,慢慢的將這篇文章逐漸完整起來。希望大家都積極評論,混個臉熟也會挺好,如果一直潛水,可能都不知道你的存在。?
之前的配置都是在內存中,下面將如何把這些數據存儲到Sql Server數據庫, 這樣更符合生產環境的要求。好啦,馬上開始今天的內容~~~
?
?(這是簡單處理了下登錄頁,要用就要好看些)
1、安裝依賴環境 ——基礎
我們要把所有的數據都存儲下來,采用接口進行建模,我們在?IdentityServer4.EntityFramework?Nuget 包中提供這些接口的 EF 實現。
算上我們上篇文章中引用的 IdentityServer4 包,一共這三個 Nuget 依賴環境:?
2、三個上下文 —— 核心
這一節大家如果看懂的話,一定會對 IdentityServer4 豐富性和可擴展性 有特別切身的了解和體會!?
Z、為什么要定義多個上下文?
為什么要多個上下文??
還記得在第二個系列 DDD 中,我們說到了多個上下文的用途,單個數據庫可以有多個上下文。例如, 如果您的數據庫包含多個數據庫架構, 并且您希望將每個架構作為單獨的自包含區域處理, 則此功能非常有用。在使用多個上下文類型時,您還會看到其他問題, 例如共享實體類型及其從一個上下文傳遞到另一個上下文等。一般來說,設計多個上下文,會使您的設計更干凈, 并分離不同的功能區域,但同時它的成本也增加了復雜性??蚣苤詴O計成多個上下文,是為了更好的擴展,我們也可以部署到不同的物理機數據庫中,更好的實現獨立性。
在我們的 IdentityServer4-EF 框架中,有三個上下文,準確來說是 2+1 個上下文,為什么這么說呢 ?
因為第三個上下文不是官方定義的,是我們自己根據需要進行合理擴展的,比如我們可以使用?Asp.Net Core 自帶的 Identity?身份認證機制來實現擴展,當然,你也可以自己定義相應的操作,如果你還不懂,就想象一下我們在 Blog.Core 項目中,我們不是自己定義的基于 JWT 的認證授權么(?用戶表 + 角色表 + 關系表等等?),但是如果你看我的 DDD 項目的話,應該可以看到我又使用了 Core 官方自帶的 Identity 機制,畢竟結合 EFCore 我們可以很快的實現用戶數據的管理,而不用自己造輪子了。
咱們這里先說說前兩個上下文,在我們使用 Ids4 的時候,有兩種類型的數據需要持久化到數據庫中:
1、配置數據(資源、客戶端、身份);//這里是對應配置上下文?ConfigurationDbContext?
2、IdentityServer在使用時產生的?操作數據(令牌,代碼和用戶的授權信息consents);//這里是對應操作上下文?PersistedGrantDbContext?
這兩個上下文以及對應的數據模型,已經被 IdentityServer4 官方給封裝好了, 我們不需要做額外的操作,直接進行遷移即可。
A:ConfigurationDb
ConfigurationDbContext (IdentityServer configuration data) ——?負責數據庫中對客戶端、資源和 CORS 設置的配置存儲;
如果需要從 EF 支持的數據庫加載客戶端、標識資源、API 資源或 CORS 數據 (而不是使用內存中配置), 則可以使用配置存儲。此支持提供 IClientStore、IResura Store 和 ICorsPolicyService?擴展性點的實現。這些實現使用名為 ConfigurationDbContext 的 dbcontext 派生類對數據庫中的表進行建模。
更多內容請查看官網 :http://docs.identityserver.io/en/latest/reference/ef.html#configuration-store-support-for-clients-resources-and-cors-settings
具體在? startup 中如何配置,下面會說到。
B:PersistedGrantDb
PersistedGrantDbContext (IdentityServer operational data.) -——?負責存儲同意、授權代碼、刷新令牌和引用令牌;
?如果需要從 EF 支持的數據庫 (而不是默認的內存數據庫) 加載授權授予、同意和令牌 (刷新和引用), 則可以使用操作存儲。此支持提供了 IPersistedGrantStore 擴展點的實現。實現使用名為?PersistedGrantDbContext? 的 dbcontext 派生類對數據庫中的表進行建模。
C:ApplicationDb
ApplicationDbContext 繼承?IdentityDbContext?(Entity Framework database context used for identity.) ——?負責與 asp. net 標識相關的用戶;
這個上下文,就是 IdentityServer4 體現?可擴展性?的關鍵點,為什么說是可擴展的,因為這是我們自己定義的,你可以在這里僅僅定義一個User表,也可以像我們的 Blog.Core 項目中,定義三個表。我們可以在這個上下文中,進行配置,來控制我們的用戶數據,當然這里看著很簡單,是因為繼承了 NetCore 官方的 Identity 了,可以使用他們的那一套邏輯。
public class ApplicationUser : IdentityUser{
//可以在這里擴展,下文會說到
}
// 定義用戶管理上下文,繼承 NetCore 自帶的 Identity 認證機制,也可以不繼承而自定義表結構。
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
}
}
這個上下文,主要是用來處理我們的用戶數據相關的部分:
1、有多少用戶數據和角色數據;
2、哪些用戶,又擁有什么角色,又對應哪些Claims 聲明。
這一塊更像是我們的平時的權限管理系統,就是在 User、Role、Claim 之間交互,文章下邊會有一個數據模型圖,會很清晰的看出來各自的對應關系。
我們既然需要用到這幾個上下文,就需要添加他們所對應的服務,別著急,往下看。?
3、配置 EF-Ids4 相關服務 —— 必要
上邊我們說到了三個上下文,如果我們直接執行遷移命令是會報錯的,比如我們直接遷移 PersistedGrantDbContext 上下文:
所以,就需要在項目中配置對應的服務,我們在 startup.cs 啟動文件中,配置服務 ConfigureService :
配置 EF 操作數據庫,很簡單,這個就按照平時我們使用的正常的方法即可:
1、獲取數據庫連接字符串:
( 我這里使用的是讀取文件的形式,其實就是字符串放到文件里了,大家自己根據需要做相應調整即可,我這么是防止密碼泄露。)
2、配置數據庫服務:
var builder = services.AddIdentityServer(options =>{
options.Events.RaiseErrorEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseSuccessEvents = true;
})
// Configures IdentityServer to use the ASP.NET Identity implementations of IUserClaimsPrincipalFactory,
// IResourceOwnerPasswordValidator, and IProfileService. Also configures some of
// ASP.NET Identity's options for use with IdentityServer (such as claim types to
// use and authenticaiton cookie settings).
// 添加配置數據(客戶端 和 資源)
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = b =>
b.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
})
// 添加操作數據 (codes, tokens, consents)
.AddOperationalStore(options =>
{
options.ConfigureDbContext = b =>
b.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
// 自動清理 token ,可選
options.EnableTokenCleanup = true;
});
?然后是我們的用戶數據存儲,其實我們可以根據自己的需要,自己建立對應的表,比如我們 Blog.Core 項目中,我們定義了用戶、角色和關系表等數據庫接口,但是這樣的話,可能少一些情況,所以一般情況下,都是采用的?asp.net core 自帶的 Identity 身份驗證,而且對擴展性很友好,就比如下文我們就對用戶主表做了自定義擴展,繼承了 IdentityUser,?ApplicationUser : IdentityUser?
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
// 啟用 Identity 服務 添加指定的用戶和角色類型的默認標識系統配置
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
4、Migrations 遷移 —— 結果
我這里提供了兩種方法,至于哪種更好,大家可以自己都試試,我都用過,可能第二種稍微多了一點,不過原理都是一樣的。
方式一:在包控制臺
一、遷移項目( 使用 Package Manager Console ):1、add-migration InitialIdentityServerPersistedGrantDbMigration -c PersistedGrantDbContext -o Data/Migrations/IdentityServer/PersistedGrantDb
2、add-migration InitialIdentityServerConfigurationDbMigration -c ConfigurationDbContext -o Data/Migrations/IdentityServer/ConfigurationDb
3、add-migration AppDbMigration -c ApplicationDbContext -o Data
4、update-database -c PersistedGrantDbContext
5、update-database -c ConfigurationDbContext
6、update-database -c ApplicationDbContext
?
最后成功的生成了我們需要的數據庫:
方式二:在命令窗口
判斷是否支持命令行遷移,你可以在項目所在的目錄下打開一個命令 Power shell 并運行命令 dotnet ef, 它應該是這樣的:
?
我是在 PowerShell 中操作的:
//1.dotnet ef migrations add InitialIdentityServerPersistedGrantDbMigration -c PersistedGrantDbContext -o Data/Migrations/IdentityServer/PersistedGrantDb//2.dotnet ef migrations add InitialIdentityServerConfigurationDbMigration -c ConfigurationDbContext -o Data/Migrations/IdentityServer/ConfigurationDb
//3.dotnet ef migrations add AppDbMigration -c ApplicationDbContext -o Data
//4.dotnet run /seed
這里我就不一一操作了,就是普通的命令執行,生成的數據庫一模一樣的。
但是要注意下,上邊我們在包管理控制臺,僅僅是遷移了數據庫,還沒有進行數據 Seed 生成,不過你看 PowerShell 的命令中的第四步,我使用? dotnet run /seed 的命令,和上邊的不一樣,沒錯,是因為下邊我用了另一種方法,通過代碼的方法進行 Migrate 了,并且同時還 Seed 了數據,那具體如何操作呢,別慌,第三節我會說到了,現在這個時候,我們已經把數據庫的所有表都已經生成好了,先不著急同步數據,我們先看看到底生成了哪些數據表。
1、整體數據模型圖
我簡單的做了下整個數據庫的數據模型圖,不同模塊用不同的顏色區分,大家也能很清楚的看出來各自對應的關系,一目了然,其中配置數據又有三個部分,分別對應的是 客戶端 + 資源 + 身份 。
?接下來,咱們針對這三個模塊簡單的說一說,因為這里還沒有數據,說起來可能會比較抽象,這里先留一個坑,等配合 Vue 客戶端使用了以后,再把完整數據展示出來,可能更好的理解了。
2、三個模塊表
操作數據模塊
?
這是 Ids4 官方封裝的第一部分——操作數據。PersistedGrants的數據,在登陸時當你同意請求許可的時候,就會在這個表里面添加一條數據。
舉個栗子,我在 Blog.Vue 項目點擊登錄,跳轉到 BlogIdp 授權中心,認證成功后,跳轉回來,就會在這個表中多了一條數據(這個功能我下次會開放出來,代碼已經寫好):
| MMD4TtLkVH7sXIwFS/DLZRfLQnUga0XMrBDVuQZWfOw= | user_consent | c2841087-1b35-4ab4-afd6-f27f80c94e6c | blogvuejs | 2019-05-08 03:35:30.0000000 | NULL | {"SubjectId":"c2841087-1b35-4ab4-afd6-f27f80c94e6c","ClientId":"blogvuejs","Scopes":["openid","profile","roles","blog.core.api"],"CreationTime":"2019-05-08T03:35:30Z","Expiration":null} |
?
配置數據模塊
?
這一大塊,是 Ids4 官方定義的第二模塊 —— 配置數據,從這里我們可以看出來 IdentityServer4 的另一個特性——豐富性,上邊咱們說到了可擴展性,它提供了豐富的配置數據結構,從三個方面來給我們定義好了這些數據,而不用我們再去一個一個的去設計,去思考。
我們可以通過這些表結構來存儲我們的服務數據,比如有哪些API資源(Blog.Core.API),哪些客戶端資源,還有用到了哪些資源等等,如果你還不清楚的,可以想想上篇文章中,我們講內存模式的 Ids4 的配置,就是這些數據,在下邊的文章中,我們會進行 Seed Data,那個時候我們再進一步看下。
具體的數據大家可以看看,截個圖:
用戶數據模塊
?
這一塊我們就很清楚了,因為這是我們自定義的用戶數據(當然本項目是直接繼承的 NetCore 的 Identity) ,光從數據庫表名上,我們就知道其中的含義了,就是用戶角色管理。
上邊咱們也簡單的說了下數據庫表結構,然后再結合三個上下文,大家應該都能明白各自的含義了,好啦,現在就是萬事俱備,只欠數據了,是時候動手了!
還記得我們上邊在生成數據庫的時候,我采用了兩個方法,第一種很常規,那接下來就說說第二種中第四步(?dotnet run /see?),是如何操作的。
1、定義 SeedData 類
首先,需要定義一個 SeedData 類,主要是用來 update-database? 和? Seed Data 這兩個作用,因為篇幅的原因,具體的代碼在 Github 上,大家自行下載查看即可:
?
2、擴展用戶主表數據
?上邊咱們也說到了,我們通過繼承使用 Identity 機制,來擴展了用戶管理,很自然的,我們需要用到 IdentityUser ,但是它的這個用戶數據肯定不能滿足我們的需求,所以,這里又一次體現了 Ids4 可擴展性的優點,我們可以自定義用戶主表:
// Add profile data for application users by adding properties to the ApplicationUser classpublic class ApplicationUser : IdentityUser
{
// 自定義屬性
public string name { get; set; }
public string RealName { get; set; }
public int sex { get; set; } = 0;
public int age { get; set; }
public DateTime birth { get; set; } = DateTime.Now;
public string addr { get; set; }
public bool tdIsDelete { get; set; }
}
3、獲取 Blog 項目用戶數據
?這個功能是一個充分不必要的條件,主要是為了解決某些項目先用了自身一套認證系統,然后又上了 IdentityServer4 項目的情況,就比如我們的 Blog.Core 項目,就是這個情況。
那用戶的數據從哪里拿到呢,很巧,大家還記得我在某一篇文章《?42 ║支持多種數據庫 & 快速數據庫生成》中,自動生成數據庫的方案,就是這么使用的,從 Github 上直接拉取數據即可,這里整個派上用場,感覺很不錯,
private static string GitJsonFileFormat = "https://github.com/anjoy8/Blog.Data.Share/raw/master/Blog.Core.Data.json/{0}.tsv";// 遠程獲取 Blog.Core 數據庫的三表數據
var BlogCore_Users = JsonHelper.ParseFormByJson<List<sysUserInfo>>(GetNetData.Get(string.Format(GitJsonFileFormat, "sysUserInfo")));
var BlogCore_Roles = JsonHelper.ParseFormByJson<List<Role>>(GetNetData.Get(string.Format(GitJsonFileFormat, "Role")));
var BlogCore_UserRoles = JsonHelper.ParseFormByJson<List<UserRole>>(GetNetData.Get(string.Format(GitJsonFileFormat, "UserRole")));
4、執行Seed方法,查看數據
經歷了定義上下文 -> 數據庫遷移 -> 獲取數據 -> Seed Data 的過程后,就剩下最后一步了,執行操作:
很簡單,我在 Blog.Core 項目中,采用的是 appsettings.json 文件配置的方法,這里換另一種方法,Program.cs 控制臺參數的形式
?在上一講中,我們用到了官方的 快速啟動 代碼,里邊已經包含了基本的頁面,當然你也可以根據自己的情況去自定義,甚至采用靜態的Ajax 來實現,我這里還是使用的 MVC 結構,只不過套用了下一個簡單樣式(樣式版權是http://www.uimaker.com/?網站的,請不要做商業用途,注意產權),至少看起來好看了一些。
?
?具體的登錄操作就不演示了,等下次把 增刪改查 都做好了,再統一做下動圖展示吧,具體如何設計,請聽下回分解。
?今天我們簡單的實現了對 IdentityServer4-EFCore 的相關配置,概念不是很難,為了加深印象,還是提幾個小問題,請大家多思考:
1、Ids4 一共用到了幾個上下文,分別的用處是什么?
2、在遷移中,數據庫生成了多少表,各個模塊又是干什么的?
3、Ids4 的良好擴展性,體現在哪里?豐富性又體現在哪里?
4、ApplicationUser 類是起到什么作用的?
5、思考1:如果同一個用戶有多個角色如何處理?
6、思考2:如果不使用 NetCore 自帶的 Identity 認證,如何自定義上下文?
https://github.com/anjoy8/Blog.IdentityServer
原文地址:https://www.cnblogs.com/laozhang-is-phi/p/10660403.html
.NET社區新聞,深度好文,歡迎訪問公眾號文章匯總?http://www.csharpkit.com?
總結
以上是生活随笔為你收集整理的从壹开始 [ Ids4实战 ] 之三║ 详解授权持久化 用户数据迁移的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 收起.NET程序的dll来
- 下一篇: 微软XAML Studio - WPF,