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
相关产品推荐
相关产品推荐

