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

ASP.NET Core 6 Web API OAuth2授权:JWKS验证AccessToken签名密钥缺失

ASP.NET Core 6 Web API OAuth2授权配置问题:[Authorize]特性返回401(签名密钥未找到)

我正在配置带有OAuth2授权的ASP.NET Core 6 Web API,目标是通过OpenID系统的JWKS端点验证AccessToken。目前手动验证Claims的接口可正常运行,但使用[Authorize]特性时,接口会返回HTTP 401未授权,响应头的WwwAuthenticate字段提示:

Bearer error="invalid_token",error_description="The signature key was not found"

我使用的是Microsoft.AspNetCore.Authentication.JwtBearer v6.0.20,排查发现ID Token包含签名密钥ID(kid),但AccessToken的kid为空。负责OpenID的团队表示该系统符合PingFederate规范,这是设计使然,建议通过JWKS端点验证AccessToken,但我不知道如何在.NET中进行相应配置。

以下是Program.Main的精简代码:

var builder = WebApplication.CreateBuilder(args);
var config = builder.Configuration;

...
builder.Services.AddSwaggerGen(opt =>
{
    opt.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
    {
        Type = SecuritySchemeType.OAuth2,
        Flows = new OpenApiOAuthFlows
        {
            AuthorizationCode = new OpenApiOAuthFlow
            {
                AuthorizationUrl = new Uri($"{config.GetValue<string>("authority")}/authorization"),
                TokenUrl = new Uri($"{config.GetValue<string>("authority")}/token")
            }
        }
    });
    opt.AddSecurityRequirement(new OpenApiSecurityRequirement
    {
        {
            new OpenApiSecurityScheme
            {
                Reference = new OpenApiReference
                {
                    Id = "oauth2",
                    Type = ReferenceType.SecurityScheme
                }
            }, new string[]{ }
        }
    });
});

builder.Services.AddAuthentication(authOpt =>
{
    authOpt.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
    .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, opt =>
    {
        opt.Authority = config.GetValue<string>("authority");
        opt.MetadataAddress = $"{config.GetValue<string>("authority")}/.well-known/openid-configuration";
        opt.Audience = "myapp";
    });
    
builder.Services.AddAuthorization(auth =>
{
    auth.AddPolicy("canread", pol => pol.RequireClaim("scope", "read:weather"));
});

var app = builder.Build();

app.UseSwagger();
// configure swagger ui auth option
app.UseSwaggerUI(opt =>
{
    opt.OAuthAppName("my app");
    opt.OAuthClientId(config.GetValue<string>("clientid"));
    opt.OAuthClientSecret(config.GetValue<string>("clientsecret"));
    opt.OAuthAdditionalQueryStringParams(new Dictionary<string, string> { { "audience", "myapp" } });
    opt.OAuthScopeSeparator(" ");
    opt.OAuthUsePkce();
});

...
// custom middleware to inspect access token is passed
app.UseMiddleware<MessageInspector>();
app.UseAuthentication();
app.UseAuthorization();

...

添加[Authorize]特性会触发签名密钥缺失错误,但以下手动验证Claims的接口可正常运行:

//[Authorize]
//[Authorize("canread", AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[HttpGet(Name = "GetWeatherForecast")]
public ActionResult<IEnumerable<WeatherForecast>> Get()
{
    var tokenStr = HttpContext.Request.Headers.Authorization.FirstOrDefault();
    var handler = new JwtSecurityTokenHandler();
    // auth token is in form "Bearer abcdefg1234567890..."
    var jwt = handler.ReadJwtToken(tokenStr.Remove(0, 7));

    if (!jwt.Claims.Where(x => x.Type == "scope" && x.Value == "read:weather").Any()) { return StatusCode(401); }

    return Ok(Enumerable.Range(1, 5).Select(index => new WeatherForecast
    {
        Date = DateTime.Now.AddDays(index),
        TemperatureC = Random.Shared.Next(-20, 55),
        Summary = Summaries[Random.Shared.Next(Summaries.Length)]
    })
    .ToArray());
}

已确认AccessToken是以"Bearer xxx"格式传递的。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 06:53:27