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

ASP.NET Core 8中如何在登录前后为用户添加自定义Claims?

在ASP.NET Core 8 + Microsoft Identity中添加自定义用户Claims

前提准备

假设你已经有继承自IdentityUser的自定义用户类(如果没有,先创建):

public class AppUser : IdentityUser
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string ImageName { get; set; }
}

并确保DbContext使用该用户类:

public class AppDbContext : IdentityDbContext<AppUser>
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
}

方式一:登录时直接添加Claims

在登录逻辑中,验证成功后获取用户属性并添加到Claims:

[HttpPost]
public async Task<IActionResult> Login(LoginViewModel model)
{
    if (!ModelState.IsValid) return View(model);

    var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
    if (result.Succeeded)
    {
        var user = await _userManager.FindByEmailAsync(model.Email);
        if (user != null)
        {
            // 获取用户已有Claims,再添加自定义项
            var claimsIdentity = new ClaimsIdentity(await _userManager.GetClaimsAsync(user));
            
            claimsIdentity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id));
            claimsIdentity.AddClaim(new Claim("FirstName", user.FirstName ?? string.Empty));
            claimsIdentity.AddClaim(new Claim("LastName", user.LastName ?? string.Empty));
            claimsIdentity.AddClaim(new Claim("ImageName", user.ImageName ?? string.Empty));

            // 更新登录身份
            await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity));
        }
        return RedirectToAction("Index", "Home");
    }

    ModelState.AddModelError(string.Empty, "登录失败,请检查账号密码");
    return View(model);
}

方式二:全局Claims转换(推荐)

通过IClaimsTransformation实现全局自动添加Claims,支持所有登录方式(Cookie/JWT等):

1. 创建自定义Claims转换器

public class CustomClaimsTransformer : IClaimsTransformation
{
    private readonly UserManager<AppUser> _userManager;
    private readonly IMemoryCache _cache;

    public CustomClaimsTransformer(UserManager<AppUser> userManager, IMemoryCache cache)
    {
        _userManager = userManager;
        _cache = cache;
    }

    public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
        var claimsIdentity = principal.Identity as ClaimsIdentity;
        if (claimsIdentity == null || !principal.Identity.IsAuthenticated)
            return principal;

        var userId = principal.FindFirstValue(ClaimTypes.NameIdentifier);
        if (string.IsNullOrEmpty(userId))
            return principal;

        // 缓存用户数据,避免频繁查库
        var user = await _cache.GetOrCreateAsync($"User_{userId}", async entry =>
        {
            entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30);
            return await _userManager.FindByIdAsync(userId);
        });

        if (user == null)
            return principal;

        // 避免重复添加Claims
        if (!claimsIdentity.HasClaim(c => c.Type == "FirstName"))
            claimsIdentity.AddClaim(new Claim("FirstName", user.FirstName ?? string.Empty));
        if (!claimsIdentity.HasClaim(c => c.Type == "LastName"))
            claimsIdentity.AddClaim(new Claim("LastName", user.LastName ?? string.Empty));
        if (!claimsIdentity.HasClaim(c => c.Type == "ImageName"))
            claimsIdentity.AddClaim(new Claim("ImageName", user.ImageName ?? string.Empty));

        return new ClaimsPrincipal(claimsIdentity);
    }
}

2. 注册服务

在Program.cs中添加:

builder.Services.AddMemoryCache();
builder.Services.AddScoped<IClaimsTransformation, CustomClaimsTransformer>();
builder.Services.AddHttpContextAccessor(); // 后续服务中访问Claims需要

访问Claims的方式

Razor页面/视图/布局中

<div class="user-info">
    <p>欢迎,@User.FindFirstValue("FirstName") @User.FindFirstValue("LastName")</p>
    @if (!string.IsNullOrEmpty(User.FindFirstValue("ImageName")))
    {
        <img src="/user-avatars/@User.FindFirstValue("ImageName")" alt="用户头像" class="avatar" />
    }
</div>

服务类中

通过IHttpContextAccessor获取当前用户Claims:

public class UserService
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public UserService(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public string GetUserFullName()
    {
        var firstName = _httpContextAccessor.HttpContext?.User.FindFirstValue("FirstName") ?? string.Empty;
        var lastName = _httpContextAccessor.HttpContext?.User.FindFirstValue("LastName") ?? string.Empty;
        return $"{firstName} {lastName}".Trim();
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 16:40:08