Identity Server 6 Invalid Scope错误排查求助
Identity Server 6 「invalid_scope Invalid scope」错误排查
错误信息
Sorry, there was an error : invalid_scope Invalid scope
应用组件
- Web Client:ASP.NET Core Razor Pages应用(端口:7091)
- Ocelot:API网关
- Identity Server 6(端口:5001)
- StripeDotNet:API
- Basket:API
现有配置代码
Identity Server 配置类
public static class Config { public static IEnumerable<IdentityResource> IdentityResources => new List<IdentityResource> { new IdentityResources.OpenId(), new IdentityResources.Profile(), // new IdentityResources.Email(), }; public static IEnumerable<ApiScope> ApiScopes => new List<ApiScope> { new ApiScope("stripedotnetapi", "StripeDotNet API") }; public static IEnumerable<Client> Clients => new List<Client> { // interactive ASP.NET Core MVC client new Client { ClientId = "razorweb", ClientName = "Razor Web", ClientSecrets = { new Secret("secret".Sha256()) }, AllowedGrantTypes = GrantTypes.Code, // 登录后重定向地址 RedirectUris = { "https://localhost:7091/signin-oidc" }, //FrontChannelLogoutUri = "https://localhost:7091/signout-callback-oidc", // 登出后重定向地址 PostLogoutRedirectUris = { "https://localhost:7091/signout-callback-oidc" }, AllowedScopes = new List<string> { IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile, // IdentityServerConstants.StandardScopes.Email, "stripedotnetapi" } } }; }
Identity Server 托管扩展
builder.Services .AddIdentityServer(options => { options.Events.RaiseErrorEvents = true; options.Events.RaiseInformationEvents = true; options.Events.RaiseFailureEvents = true; options.Events.RaiseSuccessEvents = true; options.EmitStaticAudienceClaim = true; }) .AddInMemoryIdentityResources(Config.IdentityResources) .AddInMemoryApiScopes(Config.ApiScopes) .AddInMemoryClients(Config.Clients) .AddAspNetIdentity<ApplicationUser>();
StripeDotNet API 安全配置
public static IServiceCollection AddSecurityServices(this IServiceCollection services) { services.AddAuthentication("Bearer") .AddJwtBearer(options => { options.Authority = "https://localhost:5001"; options.TokenValidationParameters.ValidateAudience = false; }); services.AddAuthorization(options => { options.AddPolicy("ApiScope", policy => { policy.RequireAuthenticatedUser(); policy.RequireClaim("scope", "stripedotnetapi"); }); }); return services; }
StripeDotNet API 控制器代码
[Route("api/[controller]")] [Authorize("ApiScope")] public class CheckoutController : BaseController { private readonly ICheckoutService _checkoutService; public CheckoutController(ICheckoutService checkoutService) { _checkoutService = Guard.Against.Null(checkoutService, nameof(checkoutService)); } [HttpGet] public async Task<IActionResult> CreateCheckoutSession([FromBody] CreateCheckoutSessionRequest req) { var response = await _checkoutService.CreateCheckoutSessionAsync(req.TenantId, req.PriceId, req.SuccessUrl, req.CancelUrl); return Ok(response); } [HttpGet("{sessionId}")] public async Task<IActionResult> GetCheckoutSession(string sessionId) { var response = await _checkoutService.GetCheckoutSessionAsync(sessionId); return Ok(response); } }
Ocelot API 网关 认证配置
var authenticationProviderKey = "IdentityApiKey"; builder.Services.AddAuthentication() .AddJwtBearer(authenticationProviderKey, x => { x.Authority = "https://localhost:5001"; // IDENTITY SERVER URL x.TokenValidationParameters = new TokenValidationParameters { ValidateAudience = false }; });
Ocelot API 网关 路由配置片段
{ "UpStreamPathTemplate": "/api/Checkout", "UpstreamHttpMethod": [ "Get" ], "DownstreamScheme": "https", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 7056 } ], "DownstreamPathTemplate": "/api/Checkout", "AuthenticationOptions": { "AuthenticationProviderKey": "IdentityApiKey", "AllowedScopes": [] } }, { "UpStreamPathTemplate": "/api/Checkout/{sessionId}", "UpstreamHttpMethod": [ "Get" ], "DownstreamScheme": "https", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 7056 } ], "DownstreamPathTemplate": "/api/Checkout/{sessionId}", "AuthenticationOptions": { "AuthenticationProviderKey": "IdentityApiKey", "AllowedScopes": [] } },
Web 客户端 安全配置
public static IServiceCollection AddSecurityServices(this IServiceCollection services) { JwtSecurityTokenHandler.DefaultMapInboundClaims = false; services.AddAuthentication(options => { options.DefaultScheme = "Cookies"; options.DefaultChallengeScheme = "oidc"; }) .AddCookie("Cookies") .AddOpenIdConnect("oidc", options => { options.Authority = "https://localhost:5001"; options.ClientId = "razorweb"; options.ClientSecret = "secret"; options.ResponseType = "code"; options.Scope.Clear(); options.Scope.Add("openid"); options.Scope.Add("profile"); //options.Scope.Add("email"); options.Scope.Add("stripedotnetapi"); options.Scope.Add("offline_access"); options.SaveTokens = true; options.GetClaimsFromUserInfoEndpoint = true; }); return services; }
发现端点返回的有效范围
"scopes_supported": [ "openid", "profile", "stripedotnetapi", "offline_access" ],
问题排查与解决建议
补充
offline_access范围的客户端授权
Web客户端请求了offline_access范围,但Identity Server的Client配置中未将该范围加入AllowedScopes。需要在Client的AllowedScopes列表中添加对应项:AllowedScopes = new List<string> { IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile, "stripedotnetapi", IdentityServerConstants.StandardScopes.OfflineAccess // 添加此行 }校验范围匹配性
确保客户端请求的所有范围,都存在于Identity Server的IdentityResources、ApiScopes以及对应Client的AllowedScopes中。清理客户端缓存
浏览器缓存的旧授权数据可能导致校验失败,尝试清除缓存或使用隐私模式重新测试。完善Ocelot网关的范围校验
当前Ocelot路由的AllowedScopes为空数组,若需要限制API访问,应添加对应范围:"AllowedScopes": ["stripedotnetapi"]查看Identity Server日志
开启Identity Server的Debug级日志,可精准定位具体是哪个范围触发了无效错误。
内容的提问来源于stack exchange,提问作者user351479
相关产品推荐
相关产品推荐

