You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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"
],

问题排查与解决建议

  1. 补充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 // 添加此行
    }
    
  2. 校验范围匹配性
    确保客户端请求的所有范围,都存在于Identity Server的IdentityResources、ApiScopes以及对应Client的AllowedScopes中。

  3. 清理客户端缓存
    浏览器缓存的旧授权数据可能导致校验失败,尝试清除缓存或使用隐私模式重新测试。

  4. 完善Ocelot网关的范围校验
    当前Ocelot路由的AllowedScopes为空数组,若需要限制API访问,应添加对应范围:

    "AllowedScopes": ["stripedotnetapi"]
    
  5. 查看Identity Server日志
    开启Identity Server的Debug级日志,可精准定位具体是哪个范围触发了无效错误。

内容的提问来源于stack exchange,提问作者user351479

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 22:45:39