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

如何正确配置IdentityServer4:Cookie登录与API的JWT授权

问题分析与解决方案

这个错误的核心原因是你的API验证JWT时指定的受众(Audience)和IdentityServer4发行的access token中的aud字段不匹配。

你当前的API配置里把jwtOptions.Audience设为了客户端ID,但IdentityServer4在Hybrid模式下,如果没有明确定义API资源,发行的access token默认受众是IDP的通用资源标识(也就是你看到的http://localhost:50059/resources),而非客户端ID。这就导致了受众验证失败。

下面是具体的解决步骤,按照顺序配置即可:

1. 在IdentityServer4端定义API资源

首先需要在IDP的配置中添加一个明确的API资源,这样发行的token会把这个资源名称作为受众之一。

添加API资源的配置代码示例:

public static IEnumerable<ApiResource> GetApiResources()
{
    return new List<ApiResource>
    {
        // 这里的"your-api-resource-name"是你给API起的唯一标识,比如"product-api"
        new ApiResource("your-api-resource-name", "Your API Display Name")
        {
            // 可选:如果需要包含额外的声明,或者配置签名算法等,可以在这里添加
            // UserClaims = { JwtClaimTypes.Name, JwtClaimTypes.Email },
            // AllowedAccessTokenSigningAlgorithms = { SecurityAlgorithms.RsaSha256 }
        }
    };
}

然后在IDP的Startup.cs中注册这个API资源:

services.AddIdentityServer()
    .AddInMemoryApiResources(Config.GetApiResources()) // 添加这一行
    .AddInMemoryClients(Config.GetClients())
    .AddInMemoryIdentityResources(Config.GetIdentityResources())
    // 其他现有配置(比如添加测试用户、认证服务等)

2. 更新客户端配置,允许访问该API资源

在IDP的客户端配置中,把刚才定义的API资源名称添加到AllowedScopes列表里,这样客户端才能请求这个资源的权限:

new Client {
    ClientId = <ClientID>,
    ClientName = <ClientName>,
    AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
    RequireConsent = true,
    ClientSecrets = { new Secret(<secret>.Sha256()) },
    AllowOfflineAccess = true,
    RedirectUris = { "http://" + ip + "/signin-oidc" },
    PostLogoutRedirectUris = { "http://" + ip + "/signout-callback-oidc" },
    AllowedScopes = {
        IdentityServerConstants.StandardScopes.OpenId,
        IdentityServerConstants.StandardScopes.Profile,
        "your-api-resource-name" // 新增这一行,对应API资源的名称
    }
};

3. 在MVC客户端请求API资源的Scope

回到你的MVC客户端的OpenID Connect配置,添加对这个API资源的Scope请求,这样登录时会获取包含该API权限的access token:

services.AddAuthentication(options => {
        options.DefaultAuthenticateScheme = "Cookies";
        options.DefaultChallengeScheme = "oidc";
    })
    .AddCookie("Cookies")
    .AddOpenIdConnect("oidc", options => {
        options.SignInScheme = "Cookies";
        options.Authority = <local IDP server with IdentityServer4>;
        options.ClientId = <ClientId>;
        options.ClientSecret = <secret>;
        options.ResponseType = "code id_token";
        options.SaveTokens = true;
        options.GetClaimsFromUserInfoEndpoint = true;
        options.Scope.Add("openid");
        options.Scope.Add("profile");
        options.Scope.Add("offline_access");
        options.Scope.Add("your-api-resource-name"); // 新增这一行
    });

4. 更新API的JWT Bearer配置

最后,把API的JWT验证配置中的Audience改成你定义的API资源名称,这样就能和token中的aud字段匹配了:

.AddJwtBearer(jwtOptions => {
    jwtOptions.Authority = <local IDP server with IdentityServer4>;
    jwtOptions.Audience = "your-api-resource-name"; // 替换成API资源的名称
    jwtOptions.SaveToken = true;
})

可选(不推荐):关闭受众验证

如果你只是临时测试,不想修改IDP配置,可以在API端关闭受众验证,但这会降低安全性,不建议在生产环境使用:

.AddJwtBearer(jwtOptions => {
    jwtOptions.Authority = <local IDP server with IdentityServer4>;
    jwtOptions.SaveToken = true;
    jwtOptions.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateAudience = false
    };
})

完成以上配置后,重新生成的access token的aud字段会包含你定义的API资源名称,API验证时就能通过受众检查了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:50:57