如何在IdentityServer4的API方法中获取客户端信息以设置默认值
在IdentityServer4 API中根据调用客户端设置默认值
我有一个基于IdentityServer4的项目,API里的创建方法需要根据调用接口的客户端(比如客户端名称)设置默认值。具体场景是:用户注册API会被多个带不同ClientId和ClientName(比如"MobileAPP"、"Website"、"CRMAPP")的客户端调用,我想根据调用的客户端给注册数据加对应的默认值。之前试着读请求上下文没找到相关信息,只找到一种客户端日志记录的方法,但没法在API方法里直接拿到客户端信息。
相关代码
客户端定义
new Client { ClientName = "Test Mobile App", ClientId = "test_mobile_app", AllowedGrantTypes = GrantTypes.ClientCredentials, ClientSecrets = { new Secret("mykey".Sha256()) }, AllowedScopes = { "app.openid", "app.profile", "user.manage" }, AllowOfflineAccess = true, RefreshTokenUsage = TokenUsage.ReUse, AccessTokenLifetime = 3600, RefreshTokenExpiration = TokenExpiration.Absolute, AbsoluteRefreshTokenLifetime = 2592000 }
策略配置
option.AddPolicy("MobileAppScope", policy => { policy.RequireAuthenticatedUser(); policy.RequireClaim("scope", "user.manage") .RequireClaim("scope", "app.openid") .RequireClaim("scope", "app.profile"); });
授权属性
[Authorize(Policy = "MobileAppScope", AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
解决方案
1. 让IdentityServer把客户端信息塞进AccessToken里
修改Client定义,添加两个关键配置,让客户端的Id和Name自动包含在AccessToken的Claims中:
new Client { ClientName = "Test Mobile App", ClientId = "test_mobile_app", AllowedGrantTypes = GrantTypes.ClientCredentials, ClientSecrets = { new Secret("mykey".Sha256()) }, AllowedScopes = { "app.openid", "app.profile", "user.manage" }, AllowOfflineAccess = true, RefreshTokenUsage = TokenUsage.ReUse, AccessTokenLifetime = 3600, RefreshTokenExpiration = TokenExpiration.Absolute, AbsoluteRefreshTokenLifetime = 2592000, // 开启客户端声明发送 AlwaysSendClientClaims = true, AlwaysIncludeUserClaimsInIdToken = true, // 可选:手动指定要包含的客户端声明(如果自动生成的不够用) Claims = new List<ClientClaim> { new ClientClaim("client_id", "test_mobile_app"), new ClientClaim("client_name", "Test Mobile App") } }
2. 配置API的JwtBearer中间件,确保声明被正确解析
在API的Program.cs(或Startup.cs)里,配置JwtBearer时,确保客户端声明不会被过滤,还能在验证后把信息存到HttpContext里:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.Authority = "https://你的IdentityServer地址"; options.Audience = "user.manage"; options.TokenValidationParameters = new TokenValidationParameters { NameClaimType = "name", RoleClaimType = "role", ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true }; // 验证Token后把客户端信息存到HttpContext,方便后续取用 options.Events = new JwtBearerEvents { OnTokenValidated = context => { var clientId = context.Principal?.FindFirst("client_id")?.Value; var clientName = context.Principal?.FindFirst("client_name")?.Value; if (!string.IsNullOrEmpty(clientId)) { context.HttpContext.Items["ClientId"] = clientId; } if (!string.IsNullOrEmpty(clientName)) { context.HttpContext.Items["ClientName"] = clientName; } return Task.CompletedTask; } }; });
3. 在API方法里直接获取客户端信息并设置默认值
现在在Controller的注册方法里,就能直接从User.Claims或者HttpContext.Items里拿到客户端信息,然后设置对应默认值:
[Authorize(Policy = "MobileAppScope", AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] [HttpPost("register")] public IActionResult RegisterUser([FromBody] UserRegisterDto dto) { // 从Claims里拿客户端信息 var clientId = User.FindFirst("client_id")?.Value; var clientName = User.FindFirst("client_name")?.Value; // 根据客户端设置默认值 if (clientName == "Test Mobile App") { dto.DefaultRole = "MobileUser"; dto.Source = "MobileApp"; } else if (clientName == "Website") { dto.DefaultRole = "WebUser"; dto.Source = "Website"; } // 执行注册逻辑... return Ok("用户注册成功"); }
4. 可选:针对不同客户端做权限控制
如果需要限制某些客户端才能调用接口,可以修改策略,加上客户端声明的校验:
option.AddPolicy("MobileAppOnly", policy => { policy.RequireAuthenticatedUser(); policy.RequireClaim("client_id", "test_mobile_app"); policy.RequireClaim("scope", "user.manage", "app.openid", "app.profile"); });
内容的提问来源于stack exchange,提问作者Syed Ahsan
相关产品推荐
相关产品推荐

