您好,登錄后才能下訂單哦!
這篇“IdentityServer4怎么使用”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“IdentityServer4怎么使用”文章吧。
OpenID是Authentication,即認證,對用戶的身份進行認證。
OAuth是一個開放標準,是Authorization,即授權,允許用戶授權第三方移動應用訪問他們存儲在其他服務商上存儲的私密的資源(如照片,視頻,聯系人列表),而無需將用戶名和密碼提供給第三方應用。OAuth允許用戶提供一個令牌而不是用戶名和密碼來訪問他們存放在特定服務商上的數據。每一個令牌授權一個特定的網站內訪問特定的資源(例如僅僅是某一相冊中的視頻)。這樣,OAuth可以允許用戶授權第三方網站訪問他們存儲在另外服務提供者的某些特定信息,而非所有內容。
OIDC是OpenID Connect的簡稱,是一個基于OAuth3協議的身份認證標準協議。是認證和授權的結合。OAuth3是一個授權協議,它無法提供完善的身份認證功能,OIDC使用OAuth3的授權服務器來為第三方客戶端提供用戶的身份認證,并把對應的身份認證信息傳遞給客戶端,且可以適用于各種類型的客戶端(比如服務端應用,移動APP,JS應用),且完全兼容OAuth3,也就是說你搭建了一個OIDC的服務后,也可以當作一個OAuth3的服務來用。
用戶訪問xxx.com(該網站支持OpenID)
xxx.com將用戶導向OpenID服務的登錄頁面
用戶輸入用戶名密碼,成功后回調到xxx.com網站,并攜帶用戶在OpenID服務中的唯一標識(這個表示可能僅僅是一個GUID,不含用戶個人信息)
xxx.com校檢成功后,就認為用戶完成了登錄認證
OpenID 目的就是做認證,使用簡單,不透露用戶的個人信息。
OAuth是用來做授權的,如果用來做認證,具體的流程如下圖所示:
用戶使用QQ登錄HelloFont
HelloFont將用戶導向QQ授權服務的登錄頁面
用戶登錄成功并授權后,頁面返回HelloFont并攜帶訪問令牌
如果想獲取用戶的詳細信息,還需要通過訪問令牌再次調用QQ服務提供的相關接口進行請求
可以看出,OAuth 相對于 OpenID 最大的區別就是,網站實際上是拿到了用戶帳戶訪問權限繼而確認你的身份。同時OAuth還比OpenID多了幾個操作步驟。
下面簡單的介紹下Identityserver4中涉及的對象,具體的可以參考下官方文檔。
用戶(User):用戶是使用已注冊的客戶端(指在id4中已經注冊)訪問資源的人。
客戶端(Client):客戶端就是從identityserver請求令牌的軟件(你可以理解為一個app即可),既可以通過身份認證令牌來驗證識別用戶身份,又可以通過授權令牌來訪問服務端的資源。但是客戶端首先必須在申請令牌前已經在identityserver服務中注冊過。
資源(Resources):資源就是你想用identityserver保護的東東,可以是用戶的身份數據或者api資源。
身份令牌(顧名思義用于做身份認證,例如sso其實主要就是用于身份認證):一個身份令牌指的就是對認證過程的描述。它至少要標識某個用戶(Called the sub aka subject claim)的主身份信息,和該用戶的認證時間和認證方式。但是身份令牌可以包含額外的身份數據,具體開發者可以自行設定,但是一般情況為了確保數據傳輸的效率,開發者一般不做過多額外的設置,大家也可以根據使用場景自行決定。
訪問令牌(用于做客戶端訪問授權):訪問令牌允許客戶端訪問某個 API 資源。客戶端請求到訪問令牌,然后使用這個令牌來訪問 API資源。訪問令牌包含了客戶端和用戶(如果有的話,這取決于業務是否需要,但通常不必要)的相關信息,API通過這些令牌信息來授予客戶端的數據訪問權限。
下面簡單的介紹下大體流程,看懂思路即可:
IDS4本身已經將OAuth3.0+OIDC+SSO思想給實現了,并且提供了成熟的組件IdentityServer4,如下圖,只需要將該組件引入,進行相關的配置即可。
正常來說我們通過nuget下載了IdentityServer4包,就需要在startup.cs中引入使用,如下:
using System; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; namespace IdentityServer { public class Startup { public IHostingEnvironment Environment { get; } public Startup(IHostingEnvironment environment) { Environment = environment; } public void ConfigureServices(IServiceCollection services) { var builder = services.AddIdentityServer() .AddInMemoryIdentityResources(Config.GetIdentityResources()) .AddInMemoryApiResources(Config.GetApis()) .AddInMemoryClients(Config.GetClients()); if (Environment.IsDevelopment()) { builder.AddDeveloperSigningCredential(); } else { throw new Exception("need to configure key material"); } } public void Configure(IApplicationBuilder app) { if (Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseIdentityServer(); } } }
可以從上面代碼看出,采用的是本地配置文件的方式,我們看下配置文件:
using IdentityServer4.Models; using System.Collections.Generic; namespace IdentityServer { public static class Config { public static IEnumerable<IdentityResource> GetIdentityResources() { return new IdentityResource[] { new IdentityResources.OpenId() }; } public static IEnumerable<ApiResource> GetApis() { return new List<ApiResource> { new ApiResource("api1", "My API") }; } public static IEnumerable<Client> GetClients() { return new List<Client> { new Client { ClientId = "client", // no interactive user, use the clientid/secret for authentication AllowedGrantTypes = GrantTypes.ClientCredentials, // secret for authentication ClientSecrets = { new Secret("secret".Sha256()) }, // scopes that client has access to AllowedScopes = { "api1" } } }; } } }
在配置文件中我們定義了身份資源IdentityResource、API資源Apis、客戶端Clients等等吧,具體怎么配置建議還是看一下官方文檔,很詳細,里面包含了相應的屬性及示例等,可根據實際需求進行選擇配置。
簡單的認證服務就搭建好了,當然這個是比較簡單的,支持客戶端模式,不需要用戶參與的授權。如果說站外應用需要使用授權碼模式、或者implact模式,我們搭建的identityserver4項目還要提供登錄授權等相關的頁面的,不然用戶在哪里登錄和授權呢。這個官網也有示例,可以在github中搜索下載源碼查看,直接使用他們提供的界面(mvc)即可,當然也可以自己進行UI優化,但是他們提供的action的名稱最好不要更改,因為identityserver4包中退出、登錄相關的跳轉都是指定好的,通過示例來說明下為啥不建議改動:
截圖中是identityserver4提供的界面代碼(mvc),有個Account控制器,里面有退出登錄、授權受限等action,如果站外應用使用授權碼模式登錄,發現授權受限或者用戶退出登錄,那么identityserver4服務會將用戶指向Account/Logout或者Account/AccessDenied,如果把名稱改了就找不到相應的action了。當然并不是所有的都不能改,比方說登錄,我就自己單獨在另一個action寫的(有需求的原因),所以需要在startup.cs引入identityserver4的時候指定,如下:
//用戶交互的選項 options.UserInteraction = new IdentityServer4.Configuration.UserInteractionOptions { LoginUrl = "/login/index",//登錄地址 };
還有一種辦法就是將identityserver4源碼進行二次開發,改成你想要的樣子。。。
上邊的identityserver4的配置信息是寫死在文件中的,在實際開發中,還是要將配置信息寫入到數據庫中,所以就需要持久化了。另外還需要提供人為配置信息的管理界面。總的來說就是基于IdentityServer4包加兩塊功能:管理界面+持久化。如下圖:
先來說持久化吧,我們先選擇EFCore作為ORM,所以startup.cs引入identityserver4的方式稍微有點不同,因為要將數據保存到數據庫中,另外還要引入efcore,來看下startup.cs:
具體代碼如下(偽代碼,主要是思路):
using HyIdentityServer4.Authorization; using HyIdentityServer4.Data; using HyIdentityServer4.Extention; using HyIdentityServer4.Implementation; using IdentityServer4.Services; using IdentityServer4.Validation; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using System; using System.IO; using System.Reflection; using System.Security.Cryptography.X509Certificates; namespace HyIdentityServer4 { public class Startup { public Startup(IConfiguration configuration, IWebHostEnvironment environment) { Configuration = configuration; Environment = environment; } public IConfiguration Configuration { get; } public IWebHostEnvironment Environment { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { //session配置 services.AddSession(options => { options.IdleTimeout = TimeSpan.FromMinutes(30); }); //cookie samesite策略 services.AddSameSiteCookiePolicy(); #region 注入EFCore服務(支持mysql和sqlserver) #if DEBUG string connectionString = Configuration.GetConnectionString("HyIds4ConnectionDebug"); #else string connectionString = Configuration.GetConnectionString("HyIds4ConnectionRelease"); #endif bool isMysql = Configuration.GetConnectionString("IsMysql").ObjToBool(); if (isMysql) { services.AddDbContext<ApplicationDbContext>(options => options.UseMySql(connectionString, MySqlServerVersion.LatestSupportedServerVersion)); } else { services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connectionString)); }; #endregion #region 注入IdentityServer4服務 var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name; var builder = services.AddIdentityServer(options => { options.Events.RaiseErrorEvents = true;//是否引發錯誤事件 options.Events.RaiseInformationEvents = true;//是否引發信息事件 options.Events.RaiseFailureEvents = true;//是否引發失敗事件 options.Events.RaiseSuccessEvents = true;//是否引發成功事件 //用戶交互的選項 options.UserInteraction = new IdentityServer4.Configuration.UserInteractionOptions { LoginUrl = "/login/index",//登錄地址 }; }) //IdentityServer4使用asp.net identity身份實現 .AddAspNetIdentity<IdentityUser>() //IdentityServer4采用EFCore的方式實現數據庫模式 .AddConfigurationStore(options => { if (isMysql) { options.ConfigureDbContext = b => b.UseMySql(connectionString, MySqlServerVersion.LatestSupportedServerVersion, sql => sql.MigrationsAssembly(migrationsAssembly)); } else { options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly)); } }) // IdentityServer4采用EFCore進行一些操作,實現持久化 .AddOperationalStore(options => { if (isMysql) { options.ConfigureDbContext = b => b.UseMySql(connectionString, MySqlServerVersion.LatestSupportedServerVersion, sql => sql.MigrationsAssembly(migrationsAssembly)); } else { options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly)); } //是否可以自動清理令牌 options.EnableTokenCleanup = true; //設置清理的間隔(頻率),以秒為單位 options.TokenCleanupInterval = 15; }); //配置證書 if (Environment.IsDevelopment()) { builder.AddDeveloperSigningCredential(); } else { builder.AddDeveloperSigningCredential(); //builder.AddSigningCredential(new X509Certificate2( // Path.Combine(Environment.ContentRootPath, Configuration["Certificates:CerPath"]), Configuration["Certificates:Password"] // )); } //https://www.javaroad.cn/questions/53540 services.AddTransient<IResourceOwnerPasswordValidator, CustomResourceOwnerPasswordValidator>();//重寫 services.AddTransient<IProfileService, CustomProfileService>();//重寫 services.AddAuthorization(options => { options.AddPolicy("超級管理員", policy => policy.Requirements.Add(new ClaimRequirement("rolename", "超級管理員"))); }); //實現此接口的類能夠決定是否授權是被允許的。 services.AddSingleton<IAuthorizationHandler, ClaimsRequirementHandler>();//重寫 #endregion services.AddControllersWithViews(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseCookiePolicy(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseSession(); app.UseStaticFiles(); app.UseSession(); app.UseRouting(); app.UseIdentityServer(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=home}/{action=index}/{id?}"); }); } } }
再來說管理界面,上邊也說到identityserver4提供了mvc的界面,如果界面要求不高可以使用這一套UI,如下圖:
當然我們也可以自定義管理界面,但是要注意的Account控制器中的action盡量和Quickstart中的保持一致,因為這里面的action涉及到了identityserver4相關的回調,如果改了名稱,就找不到action了。至于Client、API、IdentityResource、Scope等相關配置的接口就可以自定義了,只要能正確的寫入數據庫就行。
總結一下:identityserver4本身就是實現了認證和授權相關的功能,我們這里僅僅是引入identityserver4并對其進行相應的配置,這里的配置信息可以持久化到數據庫,也可以寫死在配置文件Config中。提供的界面(mvc)一方面是支持identityserver4某些授權方式(比如授權碼模式、Implict)的回調,回調的action主要是Account控制器中的action;另一方面是讓管理員配置站外應用、作用域、Api資源信息的,如下圖:
identityserver4項目提供了認證授權相關的功能,但是如果我們的認證授權項目有了管理界面,如上邊介紹的,就需要管理員,管理員可以配置客戶端、作用域等信息。但是管理員也需要權限,所以需要引入認證相關模塊,這里使用ASP.NET COREIdentity 。千萬不要混淆以下幾個概念:identityserver4、aspnet core identity、efcore。再啰嗦下,我們利用identityserver4構建了認證授權項目,在該項目中我們使用efcore實現持久化,使用aspnet core identity來認證管理員的所擁有的權限。所以在startup.cs的ConfigureServices方法中需要引入aspnetcore identity,代碼如下:
#region 注入Identity服務 //IdentityOptions文檔說明 //https://docs.microsoft.com/zh-cn/dotnet/api/microsoft.aspnetcore.builder.identityoptions?view=aspnetcore-1.1 //AddIdentity為指定的用戶和角色類型添加并配置身份系統。 services.AddIdentity<IdentityUser, IdentityRole>(options => { options.User = new UserOptions { RequireUniqueEmail = true, //要求Email唯一 AllowedUserNameCharacters = null //允許的用戶名字符 }; options.Password = new PasswordOptions { RequiredLength = 6, //要求密碼最小長度,默認是 6 個字符 RequireDigit = false, //要求有數字 RequiredUniqueChars = 0, //要求至少要出現的字母數 RequireLowercase = false, //要求小寫字母 RequireNonAlphanumeric = false, //要求特殊字符 RequireUppercase = false //要求大寫字母 }; }) //認證信息存儲的框架實現 .AddEntityFrameworkStores<ApplicationDbContext>() //令牌提供程序,用于生成重置密碼的令牌、更改電子郵件和更改電話號碼操作以及雙因素身份驗證的令牌 .AddDefaultTokenProviders(); //配置應用的cookie services.ConfigureApplicationCookie(options => { //重定向 options.LoginPath = new PathString("/login/index"); }); //配置session的有效時間,單位秒 services.AddSession(options => { options.IdleTimeout = TimeSpan.FromSeconds(180); }); #endregion
為了簡單,我們不做角色管理了(滿足了我的需求),直接寫死個角色,如下代碼,這樣該項目中的用戶就會涉及到兩個角色:普通用戶、超級管理員角色
services.AddAuthorization(options => { options.AddPolicy("超級管理員", policy => policy.Requirements.Add(new ClaimRequirement("rolename", "超級管理員"))); });
startup.cs的代碼截圖:
完整的startup.cs代碼如下:
using HyIdentityServer4.Authorization; using HyIdentityServer4.Data; using HyIdentityServer4.Extention; using HyIdentityServer4.Implementation; using IdentityServer4.Services; using IdentityServer4.Validation; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using System; using System.IO; using System.Reflection; using System.Security.Cryptography.X509Certificates; namespace HyIdentityServer4 { public class Startup { public Startup(IConfiguration configuration, IWebHostEnvironment environment) { Configuration = configuration; Environment = environment; } public IConfiguration Configuration { get; } public IWebHostEnvironment Environment { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { //session配置 services.AddSession(options => { options.IdleTimeout = TimeSpan.FromMinutes(30); }); //cookie samesite策略 services.AddSameSiteCookiePolicy(); #region 注入EFCore服務 #if DEBUG string connectionString = Configuration.GetConnectionString("HyIds4ConnectionDebug"); #else string connectionString = Configuration.GetConnectionString("HyIds4ConnectionRelease"); #endif bool isMysql = Configuration.GetConnectionString("IsMysql").ObjToBool(); if (isMysql) { services.AddDbContext<ApplicationDbContext>(options => options.UseMySql(connectionString, MySqlServerVersion.LatestSupportedServerVersion)); } else { services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connectionString)); }; #endregion #region 注入Identity服務 //IdentityOptions文檔說明 //https://docs.microsoft.com/zh-cn/dotnet/api/microsoft.aspnetcore.builder.identityoptions?view=aspnetcore-1.1 //AddIdentity為指定的用戶和角色類型添加并配置身份系統。 services.AddIdentity<IdentityUser, IdentityRole>(options => { options.User = new UserOptions { RequireUniqueEmail = true, //要求Email唯一 AllowedUserNameCharacters = null //允許的用戶名字符 }; options.Password = new PasswordOptions { RequiredLength = 1, //要求密碼最小長度,默認是 6 個字符 RequireDigit = false, //要求有數字 RequiredUniqueChars = 0, //要求至少要出現的字母數 RequireLowercase = false, //要求小寫字母 RequireNonAlphanumeric = false, //要求特殊字符 RequireUppercase = false //要求大寫字母 }; }) //認證信息存儲的框架實現 .AddEntityFrameworkStores<ApplicationDbContext>() //令牌提供程序,用于生成重置密碼的令牌、更改電子郵件和更改電話號碼操作以及雙因素身份驗證的令牌 .AddDefaultTokenProviders(); //配置應用的cookie services.ConfigureApplicationCookie(options => { //重定向 options.LoginPath = new PathString("/login/index"); }); //配置session的有效時間,單位秒 services.AddSession(options => { options.IdleTimeout = TimeSpan.FromSeconds(180); }); #endregion #region 注入IdentityServer4服務 var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name; var builder = services.AddIdentityServer(options => { options.Events.RaiseErrorEvents = true;//是否引發錯誤事件 options.Events.RaiseInformationEvents = true;//是否引發信息事件 options.Events.RaiseFailureEvents = true;//是否引發失敗事件 options.Events.RaiseSuccessEvents = true;//是否引發成功事件 //用戶交互的選項 options.UserInteraction = new IdentityServer4.Configuration.UserInteractionOptions { LoginUrl = "/login/index",//登錄地址 }; }) //IdentityServer4使用asp.net identity身份實現 .AddAspNetIdentity<IdentityUser>() //IdentityServer4采用EFCore的方式實現數據庫模式 .AddConfigurationStore(options => { if (isMysql) { options.ConfigureDbContext = b => b.UseMySql(connectionString, MySqlServerVersion.LatestSupportedServerVersion, sql => sql.MigrationsAssembly(migrationsAssembly)); } else { options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly)); } }) // IdentityServer4采用EFCore進行一些操作,實現持久化 .AddOperationalStore(options => { if (isMysql) { options.ConfigureDbContext = b => b.UseMySql(connectionString, MySqlServerVersion.LatestSupportedServerVersion, sql => sql.MigrationsAssembly(migrationsAssembly)); } else { options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly)); } //是否可以自動清理令牌 options.EnableTokenCleanup = true; //設置清理的間隔(頻率),以秒為單位 options.TokenCleanupInterval = 15; }); //配置證書 if (Environment.IsDevelopment()) { builder.AddDeveloperSigningCredential(); } else { builder.AddDeveloperSigningCredential(); //builder.AddSigningCredential(new X509Certificate2( // Path.Combine(Environment.ContentRootPath, Configuration["Certificates:CerPath"]), Configuration["Certificates:Password"] // )); } //https://www.javaroad.cn/questions/53540 services.AddTransient<IResourceOwnerPasswordValidator, CustomResourceOwnerPasswordValidator>(); services.AddTransient<IProfileService, CustomProfileService>(); services.AddAuthorization(options => { options.AddPolicy("超級管理員", policy => policy.Requirements.Add(new ClaimRequirement("rolename", "超級管理員"))); }); //實現此接口的類能夠決定是否授權是被允許的。 services.AddSingleton<IAuthorizationHandler, ClaimsRequirementHandler>(); #endregion services.AddControllersWithViews(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseCookiePolicy(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseSession(); app.UseStaticFiles(); app.UseSession(); app.UseRouting(); app.UseIdentityServer(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=home}/{action=index}/{id?}"); }); } } }
需要權限認證的action要加上Authorize,如果想了解Authorize做了哪些功能可以看下微軟官網。因為控制器比較多,所以抽象出來一個basecontroller,加上Authorize特性,需要的controller繼承basecontroller,如下:
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace HyIdentityServer4.Controllers { //[SecurityHeaders] [Authorize(Policy = "超級管理員")] public class BaseController : Controller { } }
管理員就可以通過用戶管理為用戶配置角色了:
(1)問題
Access_Token是jwt格式的,因為站外應用獲取到token后,想要從token中解析出用戶標識、用戶郵箱等信息,如何讓identityserver4項目生成的token包含這些信息呢?
(2)解決方法
為了獲得分配給用戶的聲明并將其附加到訪問令牌,需要在授權服務上實現兩個接口:IResourceOwnerPasswordValidator
和IProfileService。
以下是對這兩個類的實現:(注意請務必獲取最新版本的IdentityServer4)
public class ResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator { private readonly UserManager<ApplicationUser> _userManager; public ResourceOwnerPasswordValidator(UserManager<ApplicationUser> userManager) { _userManager = userManager; } public Task ValidateAsync(ResourceOwnerPasswordValidationContext context) { var userTask = _userManager.FindByNameAsync(context.UserName); var user = userTask.Result; context.Result = new GrantValidationResult(user.Id, "password", null, "local", null); return Task.FromResult(context.Result); } } 和 public class AspNetIdentityProfileService : IProfileService { private readonly UserManager<ApplicationUser> _userManager; public AspNetIdentityProfileService(UserManager<ApplicationUser> userManager) { _userManager = userManager; } public async Task GetProfileDataAsync(ProfileDataRequestContext context) { var subject = context.Subject; if (subject == null) throw new ArgumentNullException(nameof(context.Subject)); var subjectId = subject.GetSubjectId(); var user = await _userManager.FindByIdAsync(subjectId); if (user == null) throw new ArgumentException("Invalid subject identifier"); var claims = await GetClaimsFromUser(user); var siteIdClaim = claims.SingleOrDefault(x => x.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"); context.IssuedClaims.Add(new Claim(JwtClaimTypes.Email, user.Email)); context.IssuedClaims.Add(new Claim("siteid", siteIdClaim.Value)); context.IssuedClaims.Add(new Claim(JwtClaimTypes.Role, "User")); var roleClaims = claims.Where(x => x.Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"); foreach (var roleClaim in roleClaims) { context.IssuedClaims.Add(new Claim(JwtClaimTypes.Role, roleClaim.Value)); } } public async Task IsActiveAsync(IsActiveContext context) { var subject = context.Subject; if (subject == null) throw new ArgumentNullException(nameof(context.Subject)); var subjectId = subject.GetSubjectId(); var user = await _userManager.FindByIdAsync(subjectId); context.IsActive = false; if (user != null) { if (_userManager.SupportsUserSecurityStamp) { var security_stamp = subject.Claims.Where(c => c.Type == "security_stamp").Select(c => c.Value).SingleOrDefault(); if (security_stamp != null) { var db_security_stamp = await _userManager.GetSecurityStampAsync(user); if (db_security_stamp != security_stamp) return; } } context.IsActive = !user.LockoutEnabled || !user.LockoutEnd.HasValue || user.LockoutEnd <= DateTime.Now; } } private async Task<IEnumerable<Claim>> GetClaimsFromUser(ApplicationUser user) { var claims = new List<Claim> { new Claim(JwtClaimTypes.Subject, user.Id), new Claim(JwtClaimTypes.PreferredUserName, user.UserName) }; if (_userManager.SupportsUserEmail) { claims.AddRange(new[] { new Claim(JwtClaimTypes.Email, user.Email), new Claim(JwtClaimTypes.EmailVerified, user.EmailConfirmed ? "true" : "false", ClaimValueTypes.Boolean) }); } if (_userManager.SupportsUserPhoneNumber && !string.IsNullOrWhiteSpace(user.PhoneNumber)) { claims.AddRange(new[] { new Claim(JwtClaimTypes.PhoneNumber, user.PhoneNumber), new Claim(JwtClaimTypes.PhoneNumberVerified, user.PhoneNumberConfirmed ? "true" : "false", ClaimValueTypes.Boolean) }); } if (_userManager.SupportsUserClaim) { claims.AddRange(await _userManager.GetClaimsAsync(user)); } if (_userManager.SupportsUserRole) { var roles = await _userManager.GetRolesAsync(user); claims.AddRange(roles.Select(role => new Claim(JwtClaimTypes.Role, role))); } return claims; } }
然后需要在startup.cs中添加到你的服務:
services.AddTransient<IResourceOwnerPasswordValidator, ResourceOwnerPasswordValidator>(); services.AddTransient<IProfileService, AspNetIdentityProfileService>();
主要是引入 ITokenService 接口,調用CreateSecurityTokenAsync方法
代碼如下:
/// <summary> /// 為用戶創建token /// </summary> private async Task<TokenDto> CreateToken(Client client, CreateTokenInput input) { Token accessToken = await CreateAccessToken(client, input); string token = await _tokenService.CreateSecurityTokenAsync(accessToken); return new TokenDto() { AccessToken = token, ExpiresIn = input.Lifetime > 0 ? input.Lifetime : client.AccessTokenLifetime, TokenType = "Bearer" }; } /// <summary> /// 創建生成jwt的Token所包含信息 /// </summary> /// <param name="client"></param> /// <param name="input"></param> /// <returns></returns> private async Task<Token> CreateAccessToken(Client client, CreateTokenInput input) { #region claims //, string subjectId, int lifetime, params string[] scopes var claims = new List<Claim> { new Claim(JwtClaimTypes.ClientId, client.ClientId), new Claim(JwtClaimTypes.Id, input.SubjectId), }; input.Claims?.ForEach(c => claims.Add(c)); input.Scopes?.ForEach(s => claims.Add(new Claim(JwtClaimTypes.Scope, s))); //client scopes claims.AddRange(client.AllowedScopes.Select(s => new Claim(JwtClaimTypes.Scope, s))); #endregion #region aud var website = _configuration.GetValue<string>("AuthWebSite", "").RemoveTrailingSlash(); List<string> aud = new List<string>() { string.Concat(website, "/resources") }; //client aud:apiResourceName var apiResourceNameList = await _identityServer4Service.GetApiResourceNames(client.AllowedScopes.ToList()); aud.AddRange(apiResourceNameList ?? new List<string>()); #endregion var token = new Token(OidcConstants.TokenTypes.AccessToken) { CreationTime = DateTime.UtcNow, Claims = claims, Audiences = aud, Issuer = website, Lifetime = input.Lifetime > 0 ? input.Lifetime : client.AccessTokenLifetime, ClientId = client.ClientId, AccessTokenType = client.AccessTokenType, //Scopes = client.AllowedScopes.ToList(), }; return token; } #endregion
以上就是關于“IdentityServer4怎么使用”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。