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

ASP.NET Core中如何基于AWS Cognito不同JWT令牌标准化用户信息

我之前在项目里正好遇到过和你一模一样的AWS Cognito令牌适配场景,分享一下我是怎么实现通用User对象的,完美解决了access token和id token的信息自动填充问题:

实现步骤

1. 定义通用的AppUser模型

先创建一个包含所有可能字段的用户模型,把非access token必带的字段设为可空类型,这样不管是哪种令牌,都能生成合法的用户对象:

public class AppUser
{
    // Access Token和ID Token都携带的核心字段
    public string AccountId { get; set; } = string.Empty;
    
    // 仅ID Token携带的可选字段
    public string? FirstName { get; set; }
    public string? LastName { get; set; }
    public string? Email { get; set; }
}

2. 封装Claims提取逻辑(可选:定义Claim常量)

AWS Cognito的Claims有默认命名规则(比如given_name对应FirstName,family_name对应LastName),建议把这些Claim名称定义成常量,避免硬编码:

public static class CognitoClaimTypes
{
    public const string AccountId = "custom:AccountId"; // 替换成你Cognito配置的AccountId Claim名
    public const string FirstName = "given_name";
    public const string LastName = "family_name";
    public const string Email = "email";
}

3. 实现ClaimsPrincipal到AppUser的转换

这里提供两种常用方式,选适合你项目架构的即可:

方式一:静态扩展方法(轻量快捷)

直接给ClaimsPrincipal加扩展方法,在任何地方都能快速转换:

public static class ClaimsPrincipalExtensions
{
    public static AppUser ToAppUser(this ClaimsPrincipal principal)
    {
        var user = new AppUser();
        
        // 强制提取AccountId(两种令牌都必须携带,缺失则抛出异常)
        user.AccountId = principal.FindFirstValue(CognitoClaimTypes.AccountId) 
                         ?? throw new InvalidOperationException("AccountId Claim缺失,请检查令牌配置");
        
        // 尝试提取ID Token特有的Claims,不存在则留空
        user.FirstName = principal.FindFirstValue(CognitoClaimTypes.FirstName);
        user.LastName = principal.FindFirstValue(CognitoClaimTypes.LastName);
        user.Email = principal.FindFirstValue(CognitoClaimTypes.Email);
        
        return user;
    }
}

方式二:注入式服务(符合依赖注入原则)

如果需要更灵活的扩展(比如后续加缓存、日志),可以封装成服务:

public interface IUserResolver
{
    AppUser GetCurrentUser(ClaimsPrincipal principal);
}

public class CognitoUserResolver : IUserResolver
{
    public AppUser GetCurrentUser(ClaimsPrincipal principal)
    {
        var user = new AppUser();
        
        user.AccountId = principal.FindFirstValue(CognitoClaimTypes.AccountId) 
                         ?? throw new InvalidOperationException("AccountId Claim缺失,请检查令牌配置");
        user.FirstName = principal.FindFirstValue(CognitoClaimTypes.FirstName);
        user.LastName = principal.FindFirstValue(CognitoClaimTypes.LastName);
        user.Email = principal.FindFirstValue(CognitoClaimTypes.Email);
        
        return user;
    }
}

然后在Program.cs/Startup.cs中注册服务:

builder.Services.AddScoped<IUserResolver, CognitoUserResolver>();

4. 在AuthorizationHandler中使用通用User对象

不管用哪种转换方式,在授权逻辑里都能轻松获取标准化的用户信息:

使用扩展方法的示例:

protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, YourRequirement requirement)
{
    var appUser = context.User.ToAppUser();
    
    // 示例:根据AccountId做权限判断,或者用FirstName/Email做业务逻辑
    if (!string.IsNullOrEmpty(appUser.AccountId))
    {
        context.Succeed(requirement);
    }
    
    return Task.CompletedTask;
}

使用注入服务的示例:

public class YourAuthorizationHandler : AuthorizationHandler<YourRequirement>
{
    private readonly IUserResolver _userResolver;

    public YourAuthorizationHandler(IUserResolver userResolver)
    {
        _userResolver = userResolver;
    }

    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, YourRequirement requirement)
    {
        var appUser = _userResolver.GetCurrentUser(context.User);
        
        // 业务逻辑判断
        if (!string.IsNullOrEmpty(appUser.AccountId))
        {
            context.Succeed(requirement);
        }
        
        return Task.CompletedTask;
    }
}

5. 关键配置:确保Claims正确解析

在ASP.NET Core的JWT认证配置中,一定要关闭MapInboundClaims,避免框架自动修改Cognito的原始Claim名称:

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.Authority = "https://your-cognito-domain.auth.us-east-1.amazoncognito.com";
        options.Audience = "your-client-id";
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            // 核心配置:保留Cognito原始Claim名称,不自动映射到标准Claim类型
            MapInboundClaims = false
        };
    });

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 11:03:26