如何在Identity Server4、Angular SPA与非.NET Core WebApi中通过OIDC实现自定义Claims?
解决方案:在非.NET Core WebApi中添加应用专属自定义Claims
嘿,我之前也踩过类似的坑,给你梳理下怎么搞定这个问题,应该能帮你解决困扰:
首先得明确一个关键点:非.NET Core的Web API如果是处理客户端传来的Bearer Access Token,用UseJwtBearerAuthentication比UseOpenIdConnectAuthentication更合适——后者更多是给需要交互式登录跳转的Web应用用的。不过我两种场景都给你讲清楚:
场景1:Web API用JwtBearer验证令牌并添加自定义Claims
这是Web API最常用的方式,配置步骤如下:
- 配置JwtBearer中间件
app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions { AuthenticationMode = AuthenticationMode.Active, // 令牌验证核心参数,必须和IdentityServer4的配置匹配 TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidIssuer = "https://你的IdentityServer4地址", // 比如https://idsrv.example.com ValidateAudience = true, ValidAudience = "你的API的Audience", // 比如"api1" ValidateIssuerSigningKey = true, // 如果IdentityServer用对称加密签名,填对应的密钥;非对称的话可以从Discovery端点获取公钥 IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("你的签名密钥")), NameClaimType = JwtClaimTypes.Name, RoleClaimType = JwtClaimTypes.Role }, // 在令牌验证通过后添加自定义Claims Provider = new OAuthBearerAuthenticationProvider { OnValidateIdentity = async context => { // 获取当前用户的ClaimsIdentity var identity = context.Ticket.Identity; // 从你的应用专属数据源获取自定义信息(比如用户在这个应用里的权限、配置等) var userId = identity.FindFirst(JwtClaimTypes.Subject).Value; var appSpecificData = await GetYourAppCustomData(userId); // 替换成你的业务方法 // 添加应用专属自定义Claim identity.AddClaim(new Claim("app_custom_permission", appSpecificData)); // 更新AuthenticationTicket,让新Claim生效 context.Ticket = new AuthenticationTicket(identity, context.Ticket.Properties); } } });
场景2:如果确实要用UseOpenIdConnectAuthentication(比如Web应用风格的API)
如果你的API需要支持交互式登录跳转,那用UseOpenIdConnectAuthentication,添加自定义Claims的关键是利用SecurityTokenValidated事件:
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions { ClientId = "你的API客户端ID", Authority = "https://你的IdentityServer4地址", RedirectUri = "https://你的API地址/signin-oidc", // 登录回调地址 ResponseType = "id_token token", Scope = "openid profile api1", // 包含需要的Scope TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidIssuer = "https://你的IdentityServer4地址", ValidateAudience = true, ValidAudience = "api1", NameClaimType = JwtClaimTypes.Name, RoleClaimType = JwtClaimTypes.Role }, UseTokenLifetime = true, // 令牌验证通过后添加自定义Claims Notifications = new OpenIdConnectAuthenticationNotifications { SecurityTokenValidated = async n => { var identity = n.AuthenticationTicket.Identity; // 同样从应用专属数据源获取信息 var userId = identity.FindFirst(JwtClaimTypes.Subject).Value; var appCustomClaimValue = await GetAppSpecificData(userId); identity.AddClaim(new Claim("app_custom_setting", appCustomClaimValue)); // 更新票据 n.AuthenticationTicket = new AuthenticationTicket(identity, n.AuthenticationTicket.Properties); } } });
注意事项
- 数据源独立性:应用专属的自定义Claims不要依赖IdentityServer4返回的内容,应该从你这个Web API自己的数据库/服务里获取,这样才是真正的应用专属逻辑。
- Claim命名冲突:自定义Claim的名称最好加上应用前缀(比如
app_xxx),避免和IdentityServer返回的标准Claim重名。 - 令牌验证正确性:一定要确保
ValidIssuer、ValidAudience和签名密钥和IdentityServer4的配置完全匹配,否则中间件会直接拒绝令牌,后续的Claim添加也不会执行。
内容的提问来源于stack exchange,提问作者penleychan
相关产品推荐
相关产品推荐

