IdentityServer4中React客户端令牌无法通过C# API授权问题
问题描述
React应用通过IdentityServer4获取Access Token后,将其作为Bearer Token发送至C# API接口时始终返回未授权状态,需解决两个IdentityServer4客户端验证同一令牌的问题。
相关配置信息
IdentityServer配置
using IdentityModel; using IdentityServer4; using IdentityServer4.Models; using System.Collections.Generic; namespace IdentityServer { public class Config { public static IEnumerable<Client> Clients => new Client[] { new Client { ClientId = "react_client", ClientName = "React Client", AllowedGrantTypes = GrantTypes.Code, RequireClientSecret = false, RedirectUris = { "http://localhost:3000/registration/callback" }, PostLogoutRedirectUris = { "http://localhost:3000/registration/" }, AllowedCorsOrigins = { "https://localhost:3001" }, AllowedScopes = { IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile, "api" }, AllowAccessTokensViaBrowser = true, RequirePkce = true }, new Client { ClientId = "api", AllowedGrantTypes = GrantTypes.ClientCredentials, ClientSecrets = { new Secret("api_secret".Sha256()) }, AllowedScopes = { "api" } } }; public static IEnumerable<ApiScope> ApiScopes => new ApiScope[] { new ApiScope("api", "API") }; public static IEnumerable<ApiResource> ApiResources => new ApiResource[] { new ApiResource("api", "My API") { Scopes = { "api" } } }; public static IEnumerable<IdentityResource> IdentityResources => new IdentityResource[] { new IdentityResources.OpenId(), new IdentityResources.Profile(), new IdentityResources.Email() }; } }
React应用的C#后端Program.cs认证配置
builder.Services.AddAuthentication("Bearer") .AddJwtBearer("Bearer", options => { options.Authority = "https://localhost:7014"; options.TokenValidationParameters = new TokenValidationParameters { ValidateAudience = false, ValidateIssuerSigningKey = false, // 禁用签名密钥验证 ValidateIssuer = false, // 测试时可禁用颁发者验证 ValidateLifetime = false // 仍验证令牌有效期 }; });
受保护的C#控制器
[Authorize] [HttpGet] public async Task<ActionResult<UserDTO>> GetCurrentUser() { // 通过Email声明查找用户 var email = User.FindFirstValue(ClaimTypes.Email); var user = await _userManager.FindByEmailAsync(email); if (user == null) { return NotFound("User not found"); } UserDTO userDTO = new UserDTO { Mail = user.Email, UserName = user.UserName, DisplayName = User.FindFirstValue(ClaimTypes.Name) }; return Ok(userDTO); }
获取到的Access Token
eyJhbGciOiJSUzI1NiIsImtpZCI6IjMzQjZGRUEyRjQ4QUMxRURERTY2OTdGRkVDREQ1NUMzIiwidHlwIjoiYXQrand0In0.eyJuYmYiOjE3MDM4MDQzMjQsImV4cCI6MTcwMzgwNzkyNCwiaXNzIjoiaHR0cHM6Ly9sb2NhbGhvc3Q6NzAxNCIsImNsaWVudF9pZCI6InJlYWN0X2NsaWVudCIsInN1YiI6IkE1NUQyMUFBQjY2ODYwNERGNjc1Njk2M0M4RkQ3N0Y3NkI5Njg1NTA4QUM3RTRFQTEwNTJEQkFFNUIwMjlENTMiLCJhdXRoX3RpbWUiOjE3MDM4MDQzMjMsImlkcCI6IkF6dXJlQUQiLCJlbWFpbCI6IkJEZWxsaW5nZXJAaG9zc3JvYi5vbm1pY3Jvc29mdC5jb20iLCJuYW1lIjoiQnJ5YW4gRGVsbGluZ2VyIiwianRpIjoiQUExREJCODk0N0ZBQ0FCQjdERUVGQkUyRDE1QjI5NDIiLCJzaWQiOiIwODdCRDE2MjgyODNDN0Q1NzJEMkM5QkQ4NTI4MzlBNyIsImlhdCI6MTcwMzgwNDMyNCwic2NvcGUiOlsib3BlbmlkIiwicHJvZmlsZSJdLCJhbXIiOlsiZXh0ZXJuYWwiXX0.mpV-UYXFUrOVg91MwgBtbnF8I3p0GSFP9L1MSeeEkFWMUcXgpq88a9xrcH4DtDpiOUh9nv78bjb9ocaFvUD_DMS2ZStMcB2vVNBos72gDqMMChaobnlkNOLHDU1nG7B7Nh4FoJzDo3Isl0IxlUTeXmUC0OksbpbSyj66fZUx5y61RR8Vr6dicsXaq7E6VeN2e8zdT-_ssvozxe9R-jRkarjLarxo2KB3tRb-ysAP3jA5wDvG9rKqvv1acRIeKs9dprvUN2-3JvzRXpj2uobpBPkFqdokHf4joWiTlN-dP9S_NYzsBzgSM4w2orr83REb6KWNTkZKWx3o6nMoSiozzQ
问题分析
- 令牌缺少API访问权限:解析提供的Token可见,
scope字段仅包含openid和profile,未包含apiscope,导致API验证时判定令牌无访问权限。 - API认证配置逻辑异常:当前配置过度禁用签名密钥、颁发者等关键验证项,虽为测试场景,但可能引发验证逻辑失效;同时未正确配置受众(Audience)验证,无法匹配IdentityServer中定义的ApiResource。
- 客户端Scope请求缺失:React客户端已在IdentityServer配置中允许
apiscope,但实际请求令牌时未包含该scope,导致令牌未携带对应权限声明。
解决方案
1. 确保React客户端请求正确Scope
在React应用的OIDC配置中,明确指定请求的scope包含api,示例:
// 以oidc-client-js为例 const config = { authority: 'https://localhost:7014', client_id: 'react_client', redirect_uri: 'http://localhost:3000/registration/callback', response_type: 'code', scope: 'openid profile api' // 必须包含api };
2. 修正API的JWT验证配置
恢复必要的验证项,正确配置受众,示例:
using Microsoft.AspNetCore.Authentication.JwtBearer; builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.Authority = "https://localhost:7014"; options.Audience = "api"; // 与IdentityServer中ApiResource的名称一致 // 生产环境需启用所有验证项,测试环境可根据需求调整 options.TokenValidationParameters = new TokenValidationParameters { ValidateAudience = true, ValidateIssuerSigningKey = true, ValidateIssuer = true, ValidateLifetime = true }; });
3. 启用API中间件
在Program.cs中按顺序添加认证和授权中间件:
app.UseAuthentication(); app.UseAuthorization();
4. 验证令牌内容
使用JWT解析工具检查令牌的scope字段是否包含api,aud字段是否包含api(若启用受众验证)。
5. 可选:优化IdentityServer配置
若需令牌携带用户声明(如Email),可在ApiResource中添加用户声明:
new ApiResource("api", "My API") { Scopes = { "api" }, UserClaims = { JwtClaimTypes.Email, JwtClaimTypes.Name } };
内容的提问来源于stack exchange,提问作者Bryan Dellinger
相关产品推荐
相关产品推荐

