從壹開始 [ Ids4實(shí)戰(zhàn) ] 之三║ 詳解授權(quán)持久化 & 用戶數(shù)據(jù)遷移
哈嘍大家周三好,今天終于又重新開啟 IdentityServer4 的落地教程了,不多說,既然開始了,就要努力做好????。
書接上文,在很久之前的上篇文章《二║ 基礎(chǔ)知識集合 & 項(xiàng)目搭建一》中,我們簡單的說了說 IdentityServer4 是如何調(diào)用和配置 Token 的,主要是一些入門的基礎(chǔ)知識和概念,也算是第一次嘗鮮了,其實(shí) Ids4 本身沒有那么神秘,我們只需要知道它是一個豐富的認(rèn)證框架,又具有很好的可擴(kuò)展性,核心就是如何配置某些客戶端通過該授權(quán)服務(wù)來包括另一些資源服務(wù)器,供用戶使用。因?yàn)橹虚g隔了很長時間了,這里簡單的回顧下上篇文章說了什么,下邊這幾個小問題,相信大家腦中都能很快的有一些概念,至少是臉熟了,如果不是很清楚,請翻看上邊的鏈接,或者官網(wǎng)再看看:
1、什么是資源?什么是客戶端?什么是令牌 ?
2、IdentityServer4 主要是授權(quán)還是認(rèn)證 ?
3、OAuth 2.0、OpenID、OpenID Connect三者的關(guān)系 ?
4、Ids4 依賴的 Nuget 包是什么 ?
5、如何快速開發(fā) UI ?
今天這篇文章主要是操作和探索相結(jié)合的一篇,我看網(wǎng)上很多教程,基本上是按照官網(wǎng)概念的知識點(diǎn),配合著 Github 開源地址,講解一遍,知識是懂了,可是要是自己開發(fā)起來,還是有很多的疑惑,甚至是根本走不下去,我就從初學(xué)者的立場出發(fā),換一個思路,簡單的對其進(jìn)行探索,希望能讓初學(xué)者感興趣,而不會失去學(xué)習(xí)的沖動,當(dāng)然,這篇文章不會一下子就很完整,需要一段時間的沉淀和完善,我會不定時將學(xué)習(xí)到的感悟一一補(bǔ)充下來,然后也會和別人討論的心得寫下來,慢慢的將這篇文章逐漸完整起來。希望大家都積極評論,混個臉熟也會挺好,如果一直潛水,可能都不知道你的存在。????
之前的配置都是在內(nèi)存中,下面將如何把這些數(shù)據(jù)存儲到Sql Server數(shù)據(jù)庫, 這樣更符合生產(chǎn)環(huán)境的要求。好啦,馬上開始今天的內(nèi)容~~~
(這是簡單處理了下登錄頁,要用就要好看些)
1、安裝依賴環(huán)境 ——基礎(chǔ)
我們要把所有的數(shù)據(jù)都存儲下來,采用接口進(jìn)行建模,我們在 IdentityServer4.EntityFramework
Nuget 包中提供這些接口的 EF 實(shí)現(xiàn)。
算上我們上篇文章中引用的 IdentityServer4 包,一共這三個 Nuget 依賴環(huán)境:
2、三個上下文 —— 核心
這一節(jié)大家如果看懂的話,一定會對 IdentityServer4 豐富性和可擴(kuò)展性 有特別切身的了解和體會!????
Z、為什么要定義多個上下文?
為什么要多個上下文?
還記得在第二個系列 DDD 中,我們說到了多個上下文的用途,單個數(shù)據(jù)庫可以有多個上下文。例如, 如果您的數(shù)據(jù)庫包含多個數(shù)據(jù)庫架構(gòu), 并且您希望將每個架構(gòu)作為單獨(dú)的自包含區(qū)域處理, 則此功能非常有用。在使用多個上下文類型時,您還會看到其他問題, 例如共享實(shí)體類型及其從一個上下文傳遞到另一個上下文等。一般來說,設(shè)計多個上下文,會使您的設(shè)計更干凈, 并分離不同的功能區(qū)域,但同時它的成本也增加了復(fù)雜性??蚣苤詴O(shè)計成多個上下文,是為了更好的擴(kuò)展,我們也可以部署到不同的物理機(jī)數(shù)據(jù)庫中,更好的實(shí)現(xiàn)獨(dú)立性。
在我們的 IdentityServer4-EF 框架中,有三個上下文,準(zhǔn)確來說是 2+1 個上下文,為什么這么說呢 ?
因?yàn)榈谌齻€上下文不是官方定義的,是我們自己根據(jù)需要進(jìn)行合理擴(kuò)展的,比如我們可以使用 Asp.Net Core 自帶的 Identity 身份認(rèn)證機(jī)制來實(shí)現(xiàn)擴(kuò)展,當(dāng)然,你也可以自己定義相應(yīng)的操作,如果你還不懂,就想象一下我們在 Blog.Core 項(xiàng)目中,我們不是自己定義的基于 JWT 的認(rèn)證授權(quán)么( 用戶表 + 角色表 + 關(guān)系表等等 ),但是如果你看我的 DDD 項(xiàng)目的話,應(yīng)該可以看到我又使用了 Core 官方自帶的 Identity 機(jī)制,畢竟結(jié)合 EFCore 我們可以很快的實(shí)現(xiàn)用戶數(shù)據(jù)的管理,而不用自己造***了。
咱們這里先說說前兩個上下文,在我們使用 Ids4 的時候,有兩種類型的數(shù)據(jù)需要持久化到數(shù)據(jù)庫中:
1、配置數(shù)據(jù)(資源、客戶端、身份);//這里是對應(yīng)配置上下文
ConfigurationDbContext
2、IdentityServer在使用時產(chǎn)生的 操作數(shù)據(jù)(令牌,代碼和用戶的授權(quán)信息consents);//這里是對應(yīng)操作上下文
PersistedGrantDbContext
這兩個上下文以及對應(yīng)的數(shù)據(jù)模型,已經(jīng)被 IdentityServer4 官方給封裝好了, 我們不需要做額外的操作,直接進(jìn)行遷移即可。
A:ConfigurationDb
ConfigurationDbContext (IdentityServer configuration data) —— 負(fù)責(zé)數(shù)據(jù)庫中對客戶端、資源和 CORS 設(shè)置的配置存儲;
如果需要從 EF 支持的數(shù)據(jù)庫加載客戶端、標(biāo)識資源、API 資源或 CORS 數(shù)據(jù) (而不是使用內(nèi)存中配置), 則可以使用配置存儲。此支持提供 IClientStore、IResura Store 和 ICorsPolicyService 擴(kuò)展性點(diǎn)的實(shí)現(xiàn)。這些實(shí)現(xiàn)使用名為 ConfigurationDbContext 的 dbcontext 派生類對數(shù)據(jù)庫中的表進(jìn)行建模。
更多內(nèi)容請查看官網(wǎng) :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.) -—— 負(fù)責(zé)存儲同意、授權(quán)代碼、刷新令牌和引用令牌;
如果需要從 EF 支持的數(shù)據(jù)庫 (而不是默認(rèn)的內(nèi)存數(shù)據(jù)庫) 加載授權(quán)授予、同意和令牌 (刷新和引用), 則可以使用操作存儲。此支持提供了 IPersistedGrantStore 擴(kuò)展點(diǎn)的實(shí)現(xiàn)。實(shí)現(xiàn)使用名為 PersistedGrantDbContext 的 dbcontext 派生類對數(shù)據(jù)庫中的表進(jìn)行建模。
C:ApplicationDb
ApplicationDbContext 繼承 IdentityDbContext (Entity Framework database context used for identity.) —— 負(fù)責(zé)與 asp. net 標(biāo)識相關(guān)的用戶;
這個上下文,就是 IdentityServer4 體現(xiàn) 可擴(kuò)展性 的關(guān)鍵點(diǎn),為什么說是可擴(kuò)展的,因?yàn)檫@是我們自己定義的,你可以在這里僅僅定義一個User表,也可以像我們的 Blog.Core 項(xiàng)目中,定義三個表。我們可以在這個上下文中,進(jìn)行配置,來控制我們的用戶數(shù)據(jù),當(dāng)然這里看著很簡單,是因?yàn)槔^承了 NetCore 官方的 Identity 了,可以使用他們的那一套邏輯。
public class ApplicationUser : IdentityUser { //可以在這里擴(kuò)展,下文會說到 } // 定義用戶管理上下文,繼承 NetCore 自帶的 Identity 認(rèn)證機(jī)制,也可以不繼承而自定義表結(jié)構(gòu)。 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); } }
這個上下文,主要是用來處理我們的用戶數(shù)據(jù)相關(guān)的部分:
1、有多少用戶數(shù)據(jù)和角色數(shù)據(jù);
2、哪些用戶,又擁有什么角色,又對應(yīng)哪些Claims 聲明。
這一塊更像是我們的平時的權(quán)限管理系統(tǒng),就是在 User、Role、Claim 之間交互,文章下邊會有一個數(shù)據(jù)模型圖,會很清晰的看出來各自的對應(yīng)關(guān)系。
我們既然需要用到這幾個上下文,就需要添加他們所對應(yīng)的服務(wù),別著急,往下看。
3、配置 EF-Ids4 相關(guān)服務(wù) —— 必要
上邊我們說到了三個上下文,如果我們直接執(zhí)行遷移命令是會報錯的,比如我們直接遷移 PersistedGrantDbContext 上下文:
所以,就需要在項(xiàng)目中配置對應(yīng)的服務(wù),我們在 startup.cs 啟動文件中,配置服務(wù) ConfigureService :
配置 EF 操作數(shù)據(jù)庫,很簡單,這個就按照平時我們使用的正常的方法即可:
1、獲取數(shù)據(jù)庫連接字符串:
( 我這里使用的是讀取文件的形式,其實(shí)就是字符串放到文件里了,大家自己根據(jù)需要做相應(yīng)調(diào)整即可,我這么是防止密碼泄露。)
2、配置數(shù)據(jù)庫服務(wù):
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).
.AddAspNetIdentity<ApplicationUser>() // 添加配置數(shù)據(jù)(客戶端 和 資源) .AddConfigurationStore(options => { options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly)); }) // 添加操作數(shù)據(jù) (codes, tokens, consents) .AddOperationalStore(options => { options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly)); // 自動清理 token ,可選 options.EnableTokenCleanup = true; });
然后是我們的用戶數(shù)據(jù)存儲,其實(shí)我們可以根據(jù)自己的需要,自己建立對應(yīng)的表,比如我們 Blog.Core 項(xiàng)目中,我們定義了用戶、角色和關(guān)系表等數(shù)據(jù)庫接口,但是這樣的話,可能少一些情況,所以一般情況下,都是采用的 asp.net core 自帶的 Identity 身份驗(yàn)證,而且對擴(kuò)展性很友好,就比如下文我們就對用戶主表做了自定義擴(kuò)展,繼承了 IdentityUser, ApplicationUser : IdentityUser
// 數(shù)據(jù)庫配置系統(tǒng)應(yīng)用用戶數(shù)據(jù)上下文 services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connectionString)); // 啟用 Identity 服務(wù) 添加指定的用戶和角色類型的默認(rèn)標(biāo)識系統(tǒng)配置 services.AddIdentity<ApplicationUser, IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders();
4、Migrations 遷移 —— 結(jié)果
我這里提供了兩種方法,至于哪種更好,大家可以自己都試試,我都用過,可能第二種稍微多了一點(diǎn),不過原理都是一樣的。
方式一:在包控制臺
一、遷移項(xiàng)目( 使用 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
最后成功的生成了我們需要的數(shù)據(jù)庫:
方式二:在命令窗口
判斷是否支持命令行遷移,你可以在項(xiàng)目所在的目錄下打開一個命令 Power shell 并運(yùn)行命令 dotnet ef, 它應(yīng)該是這樣的:
我是在 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
這里我就不一一操作了,就是普通的命令執(zhí)行,生成的數(shù)據(jù)庫一模一樣的。
但是要注意下,上邊我們在包管理控制臺,僅僅是遷移了數(shù)據(jù)庫,還沒有進(jìn)行數(shù)據(jù) Seed 生成,不過你看 PowerShell 的命令中的第四步,我使用 dotnet run /seed 的命令,和上邊的不一樣,沒錯,是因?yàn)橄逻呂矣昧肆硪环N方法,通過代碼的方法進(jìn)行 Migrate 了,并且同時還 Seed 了數(shù)據(jù),那具體如何操作呢,別慌,第三節(jié)我會說到了,現(xiàn)在這個時候,我們已經(jīng)把數(shù)據(jù)庫的所有表都已經(jīng)生成好了,先不著急同步數(shù)據(jù),我們先看看到底生成了哪些數(shù)據(jù)表。
1、整體數(shù)據(jù)模型圖
我簡單的做了下整個數(shù)據(jù)庫的數(shù)據(jù)模型圖,不同模塊用不同的顏色區(qū)分,大家也能很清楚的看出來各自對應(yīng)的關(guān)系,一目了然,其中配置數(shù)據(jù)又有三個部分,分別對應(yīng)的是 客戶端 + 資源 + 身份 。
接下來,咱們針對這三個模塊簡單的說一說,因?yàn)檫@里還沒有數(shù)據(jù),說起來可能會比較抽象,這里先留一個坑,等配合 Vue 客戶端使用了以后,再把完整數(shù)據(jù)展示出來,可能更好的理解了。
2、三個模塊表
操作數(shù)據(jù)模塊
這是 Ids4 官方封裝的第一部分——操作數(shù)據(jù)。PersistedGrants的數(shù)據(jù),在登陸時當(dāng)你同意請求許可的時候,就會在這個表里面添加一條數(shù)據(jù)。
舉個栗子,我在 Blog.Vue 項(xiàng)目點(diǎn)擊登錄,跳轉(zhuǎn)到 BlogIdp 授權(quán)中心,認(rèn)證成功后,跳轉(zhuǎn)回來,就會在這個表中多了一條數(shù)據(jù)(這個功能我下次會開放出來,代碼已經(jīng)寫好):
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} |
配置數(shù)據(jù)模塊
這一大塊,是 Ids4 官方定義的第二模塊 —— 配置數(shù)據(jù),從這里我們可以看出來 IdentityServer4 的另一個特性——豐富性,上邊咱們說到了可擴(kuò)展性,它提供了豐富的配置數(shù)據(jù)結(jié)構(gòu),從三個方面來給我們定義好了這些數(shù)據(jù),而不用我們再去一個一個的去設(shè)計,去思考。
我們可以通過這些表結(jié)構(gòu)來存儲我們的服務(wù)數(shù)據(jù),比如有哪些API資源(Blog.Core.API),哪些客戶端資源,還有用到了哪些資源等等,如果你還不清楚的,可以想想上篇文章中,我們講內(nèi)存模式的 Ids4 的配置,就是這些數(shù)據(jù),在下邊的文章中,我們會進(jìn)行 Seed Data,那個時候我們再進(jìn)一步看下。
具體的數(shù)據(jù)大家可以看看,截個圖:
用戶數(shù)據(jù)模塊
這一塊我們就很清楚了,因?yàn)檫@是我們自定義的用戶數(shù)據(jù)(當(dāng)然本項(xiàng)目是直接繼承的 NetCore 的 Identity) ,光從數(shù)據(jù)庫表名上,我們就知道其中的含義了,就是用戶角色管理。
上邊咱們也簡單的說了下數(shù)據(jù)庫表結(jié)構(gòu),然后再結(jié)合三個上下文,大家應(yīng)該都能明白各自的含義了,好啦,現(xiàn)在就是萬事俱備,只欠數(shù)據(jù)了,是時候動手了!
還記得我們上邊在生成數(shù)據(jù)庫的時候,我采用了兩個方法,第一種很常規(guī),那接下來就說說第二種中第四步( dotnet run /see ),是如何操作的。
1、定義 SeedData 類
首先,需要定義一個 SeedData 類,主要是用來 update-database 和 Seed Data 這兩個作用,因?yàn)槠脑颍唧w的代碼在 Github 上,大家自行下載查看即可:
2、擴(kuò)展用戶主表數(shù)據(jù)
上邊咱們也說到了,我們通過繼承使用 Identity 機(jī)制,來擴(kuò)展了用戶管理,很自然的,我們需要用到 IdentityUser ,但是它的這個用戶數(shù)據(jù)肯定不能滿足我們的需求,所以,這里又一次體現(xiàn)了 Ids4 可擴(kuò)展性的優(yōu)點(diǎn),我們可以自定義用戶主表:
// Add profile data for application users by adding properties to the ApplicationUser class public 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 項(xiàng)目用戶數(shù)據(jù)
這個功能是一個充分不必要的條件,主要是為了解決某些項(xiàng)目先用了自身一套認(rèn)證系統(tǒng),然后又上了 IdentityServer4 項(xiàng)目的情況,就比如我們的 Blog.Core 項(xiàng)目,就是這個情況。
那用戶的數(shù)據(jù)從哪里拿到呢,很巧,大家還記得我在某一篇文章《 42 ║支持多種數(shù)據(jù)庫 & 快速數(shù)據(jù)庫生成》中,自動生成數(shù)據(jù)庫的方案,就是這么使用的,從 Github 上直接拉取數(shù)據(jù)即可,這里整個派上用場,感覺很不錯,
private static string GitJsonFileFormat = "https://github.com/anjoy8/Blog.Data.Share/raw/master/Blog.Core.Data.json/{0}.tsv"; // 遠(yuǎn)程獲取 Blog.Core 數(shù)據(jù)庫的三表數(shù)據(jù) 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、執(zhí)行Seed方法,查看數(shù)據(jù)
經(jīng)歷了定義上下文 -> 數(shù)據(jù)庫遷移 -> 獲取數(shù)據(jù) -> Seed Data 的過程后,就剩下最后一步了,執(zhí)行操作:
很簡單,我在 Blog.Core 項(xiàng)目中,采用的是 appsettings.json 文件配置的方法,這里換另一種方法,Program.cs 控制臺參數(shù)的形式
在上一講中,我們用到了官方的 快速啟動 代碼,里邊已經(jīng)包含了基本的頁面,當(dāng)然你也可以根據(jù)自己的情況去自定義,甚至采用靜態(tài)的Ajax 來實(shí)現(xiàn),我這里還是使用的 MVC 結(jié)構(gòu),只不過套用了下一個簡單樣式(樣式版權(quán)是http://www.uimaker.com/ 網(wǎng)站的,請不要做商業(yè)用途,注意產(chǎn)權(quán)),至少看起來好看了一些。
具體的登錄操作就不演示了,等下次把 增刪改查 都做好了,再統(tǒng)一做下動圖展示吧,具體如何設(shè)計,請聽下回分解。
今天我們簡單的實(shí)現(xiàn)了對 IdentityServer4-EFCore 的相關(guān)配置,概念不是很難,為了加深印象,還是提幾個小問題,請大家多思考:
1、Ids4 一共用到了幾個上下文,分別的用處是什么?
2、在遷移中,數(shù)據(jù)庫生成了多少表,各個模塊又是干什么的?
3、Ids4 的良好擴(kuò)展性,體現(xiàn)在哪里?豐富性又體現(xiàn)在哪里?
4、ApplicationUser 類是起到什么作用的?
5、思考1:如果同一個用戶有多個角色如何處理?
6、思考2:如果不使用 NetCore 自帶的 Identity 認(rèn)證,如何自定義上下文?
https://github.com/anjoy8/Blog.IdentityServer
原文地址:https://www.cnblogs.com/laozhang-is-phi/p/10660403.html
04 ║ 用戶數(shù)據(jù)管理 & 前后端授權(quán)聯(lián)調(diào) https://www.cnblogs.com/laozhang-is-phi/p/10911438.html
https://github.com/anjoy8/Blog.IdentityServer