今天为大家介绍的是关于IdentityServer4介绍和使用,感兴趣的小伙伴一起来看看吧。
OpenID 目的就是做认证,使用简单,不透露用户的个人信息。
OAuth是用来做授权的,如果用来做认证,具体的流程如下图所示:
可以看出,OAuth 相对于 OpenID 最大的区别就是,网站实际上是拿到了用户帐户访问权限继而确认你的身份。同时OAuth还比OpenID多了几个操作步骤。
下面简单的介绍下Identityserver4中涉及的对象,具体的可以参考下官方文档。
下面简单的介绍下大体流程,看懂思路即可:
IDS4本身已经将OAuth2.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 IEnumerableGetIdentityResources() { return new IdentityResource[] { new IdentityResources.OpenId() }; } public static IEnumerable GetApis() { return new List { new ApiResource("api1", "My API") }; } public static IEnumerable GetClients() { return new List { 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(options => options.UseMySql(connectionString, MySqlServerVersion.LatestSupportedServerVersion)); } else { services.AddDbContext (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 () //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 ();//重写 services.AddTransient ();//重写 services.AddAuthorization(options => { options.AddPolicy("超级管理员", policy => policy.Requirements.Add(new ClaimRequirement("rolename", "超级管理员"))); }); //实现此接口的类能够决定是否授权是被允许的。 services.AddSingleton ();//重写 #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(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 () //令牌提供程序,用于生成重置密码的令牌、更改电子邮件和更改电话号码操作以及双因素身份验证的令牌 .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(options => options.UseMySql(connectionString, MySqlServerVersion.LatestSupportedServerVersion)); } else { services.AddDbContext (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 (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 () //令牌提供程序,用于生成重置密码的令牌、更改电子邮件和更改电话号码操作以及双因素身份验证的令牌 .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 () //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 (); services.AddTransient (); services.AddAuthorization(options => { options.AddPolicy("超级管理员", policy => policy.Requirements.Add(new ClaimRequirement("rolename", "超级管理员"))); }); //实现此接口的类能够决定是否授权是被允许的。 services.AddSingleton (); #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_userManager; public ResourceOwnerPasswordValidator(UserManager 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 _userManager; public AspNetIdentityProfileService(UserManager 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 > GetClaimsFromUser(ApplicationUser user) { var claims = new List { 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(); services.AddTransient ();
主要是引入 ITokenService 接口,调用CreateSecurityTokenAsync方法
代码如下:
////// 为用户创建token /// private async TaskCreateToken(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" }; } /// /// 创建生成jwt的Token所包含信息 /// /// /// ///private async Task CreateAccessToken(Client client, CreateTokenInput input) { #region claims //, string subjectId, int lifetime, params string[] scopes var claims = new List { 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 ("AuthWebSite", "").RemoveTrailingSlash(); List aud = new List () { string.Concat(website, "/resources") }; //client aud:apiResourceName var apiResourceNameList = await _identityServer4Service.GetApiResourceNames(client.AllowedScopes.ToList()); aud.AddRange(apiResourceNameList ?? new List ()); #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介绍和使用的全部内容了,感兴趣的小伙伴记得点击关注哦。