IdentityServer4授權和認證對接數據庫
接著上一篇講:https://www.cnblogs.com/nsky/p/10352678.html
我們之前都是用in-men的方式把數據添加到內存了,目的是為了測試方便,
現在我們把所有配置都添加到數據庫中
用IdeneityServer4 + EntityFramework + ASP.NET Identity的方式
上篇已經講過identity和profile的對接,這裏講講配置信息
之前都是這樣做的
添加包:IdentityServer4.EntityFramework
裏面有專門的2個DbContext管理對應的信息
分別是:PersistedGrantDbContext 和 ConfigurationDbContext
如果還記得Identity,裏面有個ApplicationDbContext
所以這裏總共有3個DbContext
ApplicationDbContext
PersistedGrantDbContext
ConfigurationDbContext
ApplicationDbContext - 負責涉及ASP.NET Identity的用戶所以表
dbo.AspNetRoleClaims
dbo.AspNetRoles
dbo.AspNetUserClaims
dbo.AspNetUserLogins
dbo.AspNetUserRoles
dbo.AspNetUsers
dbo.AspNetUserTokens
PersistedGrantDbContext - 負責存儲同意,授權代碼,刷新令牌和引用令牌
dbo.PersistedGrants
ConfigurationDbContext - 負責數據庫中剩余的所有其他內容
所以關於遷移,如果我更新任何AspNet Identity模型(即ApplicationUser),那麽我將在ApplicationDbContext上運行遷移。任何客戶端表或其他範圍都將在ConfigurationDbContext上運行。並且訪問entites(或表)將是相應的上下文。
添加包之後,添加依賴註入配置
.AddConfigurationStore(options => { options.ConfigureDbContext= builder => { builder.UseSqlServer(Configuration.GetConnectionString("conn"), sql => sql.MigrationsAssembly(migrationAssembly)); }; }) /* 這裏存儲的是,給用戶授權的token和一些授權信息 添加來自數據庫的操作數據(codes, tokens, consents) */ .AddOperationalStore(options => { options.ConfigureDbContext = builder => { builder.UseSqlServer(Configuration.GetConnectionString("conn"), sql => sql.MigrationsAssembly(migrationAssembly)); }; })
migrationAssembly是當前程序集;
var migrationAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
接下來生成migration,在項目的程序包管理控制臺輸入:
Add-Migration InitConfiguration -Context ConfigurationDbContext -o Date\Migrations\IdentityServer\ConfiguragtionDb
Add-Migration InitConfiguration -Context PersistedGrantDbContext -o Date\Migrations\IdentityServer\PersistedGrantDb
這樣就添加了兩個migration
執行update-database生成表
update-database -context ConfigurationDbContext
Update-Database -Context PersistedGrantDbContext
這樣就生成了表
因為現在還沒有界面錄入,可以先手動初始化配置文件 到數據庫,因為之前有config.cs
可以直接映射到model寫入數據庫
/// <summary> /// 因為現在沒有通過UI去錄入api,client等信息 /// 所有可以先init一些默認信息寫入數據庫 /// </summary> /// <param name="app"></param> public void InitIdentityServerDataBase(IApplicationBuilder app) { //ApplicationServices返回的就是IServiceProvider,依賴註入的容器 using (var scope = app.ApplicationServices.CreateScope()) { //Update-Database scope.ServiceProvider.GetService<PersistedGrantDbContext>().Database.Migrate(); //var provide = scope.ServiceProvider.GetService<PersistedGrantDbContext>(); //ckk.PersistedGrants.Add(new IdentityServer4.EntityFramework.Entities.PersistedGrant { //}); var configurationDbContext = scope.ServiceProvider.GetRequiredService<ConfigurationDbContext>(); /* 如果不走這個, 那麽應該手動執行 Update-Database -Context PersistedGrantDbContext */ configurationDbContext.Database.Migrate(); if (!configurationDbContext.Clients.Any()) { foreach (var client in Config.GetClients()) { //client.ToEntity() 會把當前實體映射到EF實體 configurationDbContext.Clients.Add(client.ToEntity()); } configurationDbContext.SaveChanges(); } if (!configurationDbContext.ApiResources.Any()) { foreach (var api in Config.GetApiResources()) { configurationDbContext.ApiResources.Add(api.ToEntity()); } configurationDbContext.SaveChanges(); } if (!configurationDbContext.IdentityResources.Any()) { foreach (var identity in Config.GetIdentityResource()) { configurationDbContext.IdentityResources.Add(identity.ToEntity()); } configurationDbContext.SaveChanges(); } } }
在Configure中調用
InitIdentityServerDataBase(app);
dotnet run就有數據了
客戶端不用配置,
獲取refresh_token,混合模式是支持refresh_token的
詳情:https://www.cnblogs.com/jesse2013/p/oidc-in-aspnetcore-with-identity-server.html
IdentityResource新增offline_access身份
AllowedScopes可以不用加: IdentityServerConstants.StandardScopes.OfflineAccess
服務端Client設置允許: AllowOfflineAccess = true,
客戶端配置:options.Scope.Add("offline_access");
拿到這個refresh_token,可以刷新access_token
一個refresh_token只能用一次,否則:
通過這個access_token就看訪問資源api了
但就算授權了。也只能訪問授權的api
identityResurce是資源信息,AllowedScopes設置了
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Email,
IdentityServerConstants.StandardScopes.Profile,
就會返回這些信息,
OpenId是必須要的,因為OIDC要通過openid確認身份
Profile是可選的,只是客戶端默認是傳了Profile的,
因為oidc就是為了返回用信息而來的
Profile包含了一些基本的信息
name
family_name
given_name
middle_name
nickname
preferred_username
profile
picture
website
gender
birthdate
zoneinfo
locale
updated_at
Email包含了email 和 email_verified
這些從源碼可以看到:
https://github.com/IdentityServer/IdentityServer4/blob/63a50d7838af25896fbf836ea4e4f37b5e179cd8/src/Constants.cs
所以客戶端獲取的cliams是這些
因為profile是在我們的ProfileServices類返回的
那麽如果用戶沒有選擇
是不是應該不返回profile信息呢?
GetProfileDataAsync方法的context可以拿到當前請求的IdentityResources和ApiResource
好像通過 var claimTypes = context.RequestedClaimTypes;也可以判斷,選擇了profile,那麽RequestedClaimTypes是有值的
當然除了了一些基本信息外,客戶端還想獲取其他資源,這也是可以的
比如資源服務器有個接口,獲取額外的新,scope叫:OtherInfo
客戶端請求scope:options.Scope.Add("OtherInfo");
可以看到上面是身份信息,就是會返回的的用戶信息
下面是權限,就是可以去資源服務器獲取的那些權限,因為:access toke管的是權限
1:先不選擇,拿到是access_token裏面的scope是沒有OtherInfo的
這裏為啥有兩個offline_access?我也不知道
2:如果選擇的話。如果不出錯的話是有的
那麽資源服務器就可以根據當前這個scope來判斷了
[HttpGet] public ActionResult GetOtherInfo() { //判斷是否授權 var scope = User.Claims.FirstOrDefault(f => f.Type == "scope" && f.Value == "OtherInfo"); if (scope != null) { return new JsonResult( new { phone = "110", address = "china", age = "20", gender = "m", hobby = "coding" } ); } else //禁止訪問 { return BadRequest(StatusCodes.Status403Forbidden); } }
如果授權請求了OtherInfo請求是成功了
當沒有授權OtherInfo的時候,當然,返回什麽信息你可以自己定義
這說明你只有權限訪問資源服務器,授權了的api。
如果你的access_token是錯誤的。就說明你沒有授權,你都沒有機會進入api,會提示401
目前我想到的方法就是這樣,也許不是最好的
既然access_token包含profile信息,它又是JWT類型,那是不是可以DeCode呢?
答案是可以的:
界面輸出
參考:https://cloud.tencent.com/developer/article/1048128
IdentityServer4授權和認證對接數據庫