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

使用Identity Server4在.NET微服务中遇鉴权问题:获取用户信息被禁止

排查IdentityServer4鉴权403及preferred_username缺失问题

1. 验证API的Audience与Token的Audience匹配

API服务必须配置正确的Audience,确保和IdentityServer4中定义的ApiResource名称一致。如果不匹配,Token会被判定为无效,直接返回403。

API启动类配置示例:

services.AddAuthentication("Bearer")
    .AddJwtBearer("Bearer", options =>
    {
        options.Authority = "https://your-identity-server-url";
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateAudience = true,
            ValidAudience = "your-api-resource-name", // 必须和IdentityServer中ApiResource的Name一致
            ValidateIssuer = true,
            ValidIssuer = "https://your-identity-server-url"
        };
    });

IdentityServer中ApiResource配置示例:

public static IEnumerable<ApiResource> GetApiResources()
{
    return new List<ApiResource>
    {
        new ApiResource("your-api-resource-name", "Your API Display Name")
        {
            Scopes = { "your-api-scope" }
        }
    };
}

2. 确认登录请求包含必要的Scope

preferred_username属于profile scope,API调用需要对应的业务scope。如果登录时未请求这些scope,Token中会缺失相应Claim,导致403或无法获取用户名。

前端登录请求需包含的scope示例:

scope: "openid profile your-api-scope"

3. 检查IdentityServer的ProfileService实现

默认ProfileService不会自动返回所有用户Claim,需自定义实现IProfileService确保preferred_username被加入Token。

自定义ProfileService示例:

public class CustomProfileService : IProfileService
{
    private readonly UserManager<ApplicationUser> _userManager;

    public CustomProfileService(UserManager<ApplicationUser> userManager)
    {
        _userManager = userManager;
    }

    public async Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
        var user = await _userManager.GetUserAsync(context.Subject);
        if (user == null)
            throw new ArgumentException("Invalid user");

        var claims = new List<Claim>
        {
            new Claim(JwtClaimTypes.PreferredUserName, user.UserName)
            // 可添加其他需要返回的Claim
        };

        context.IssuedClaims.AddRange(claims);
    }

    public async Task IsActiveAsync(IsActiveContext context)
    {
        var user = await _userManager.GetUserAsync(context.Subject);
        context.IsActive = user != null;
    }
}

在IdentityServer启动类中注册该服务:

services.AddScoped<IProfileService, CustomProfileService>();

4. 验证Client配置的Claim包含规则

在IdentityServer的Client配置中,需确保允许返回用户Claim到Token中,同时在AllowedScopes里包含profile。

Client配置示例:

public static IEnumerable<Client> GetClients()
{
    return new List<Client>
    {
        new Client
        {
            ClientId = "your-client-id",
            ClientSecrets = { new Secret("your-client-secret".Sha256()) },
            AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
            AllowedScopes = { "openid", "profile", "your-api-scope" },
            AlwaysIncludeUserClaimsInIdToken = true, // 确保用户Claim被包含进Token
            AllowOfflineAccess = true
        }
    };
}

5. 检查API的授权策略

如果[Authorize]使用了自定义策略,需确保Token中的Claim满足策略要求。例如:

自定义策略配置:

services.AddAuthorization(options =>
{
    options.AddPolicy("RequirePreferredUserName", policy =>
        policy.RequireClaim(JwtClaimTypes.PreferredUserName));
});

此时控制器需使用[Authorize(Policy = "RequirePreferredUserName")],若Token中无该Claim则返回403。

6. 确认使用正确的Token类型

调用API必须使用Access Token,而非Id Token。Id Token的受众是客户端,而非API,用它调用API会因Audience不匹配导致403。可通过JWT.io解析Token,查看aud字段确认是否为API的Audience。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 21:52:43