在ASP.NET Core Blazor Server登录时为用户添加Identity声明
编辑2:
最终已解决,可查看下方已接受答案。
编辑:
按照@Jason Pan的指导,我已上传完整的尝试代码。
我在登录过程中添加了声明(位于Login.cshtml.cs文件),并尝试从Razor组件中访问这些声明。
遗憾的是,此尝试未成功,我获取到的声明值始终为null。😔
原始问题
我已查阅过一些类似问题,但它们对我的场景并无帮助。
我的项目是一个Blazor Server应用,已按照官方步骤集成了Identity。
我希望实现以下需求:
- 用户输入登录凭据。
- 若用户名在Active Directory中有效,则从中获取
EmployeeId字段。 - 使用
SignInManager.PasswordSignInAsync验证用户身份。 - 将
EmployeeId作为声明添加到ClaimsPrincipal中(以便我可以在Razor组件中通过级联参数的方式使用EmployeeId)。
我正纠结于如何在登录过程中将EmployeeId添加为声明。
我的Login.cshtml.cs中的OnPostAsync方法代码如下:
public class LoginModel : PageModel { private readonly SignInManager<MMTUser> _signInManager; private readonly ILogger<LoginModel> _logger; public LoginModel(SignInManager<MMTUser> signInManager, ILogger<LoginModel> logger) { _signInManager = signInManager; _logger = logger; } [BindProperty] public InputModel Input { get; set; } public string ReturnUrl { get; set; } [TempData] public string ErrorMessage { get; set; } public async Task<IActionResult> OnPostAsync(string returnUrl = null) { returnUrl ??= Url.Content("~/"); if (ModelState.IsValid) { // Step 1: Check if this user exists in our AD // If YES: Grab the Employee Id and go to next step // If NO: Terminate the process var adLookupResult = ADHelper.ADLookup(Input.Username); if (adLookupResult == null || string.IsNullOrEmpty(adLookupResult.EmployeeId)) { ModelState.AddModelError(string.Empty, "Invalid login attempt."); return Page(); } // Step 2: SignIn the user var result = await _signInManager.PasswordSignInAsync(Input.Username, Input.Password, isPersistent: Input.RememberMe, lockoutOnFailure: false); // Step 3: How do I add adLookupResult.EmployeeId to the ClaimsPrincipal? if (result.Succeeded) { _logger.LogInformation("User logged in."); return LocalRedirect(returnUrl); } else { ModelState.AddModelError(string.Empty, "Invalid login attempt."); return Page(); } } // If we got this far, something failed, redisplay form return Page(); } public class InputModel { [Required] public string Username { get; set; } [Required] [DataType(DataType.Password)] public string Password { get; set; } [Display(Name = "Remember me?")] public bool RememberMe { get; set; } } }
解决方案
要在登录过程中动态添加EmployeeId声明,不能直接在PasswordSignInAsync之后修改ClaimsPrincipal,因为该方法已经完成了登录凭据的生成。正确的做法是手动生成用户主体,添加声明后再完成登录:
修改OnPostAsync方法中登录相关的代码段:
if (ModelState.IsValid) { var adLookupResult = ADHelper.ADLookup(Input.Username); if (adLookupResult == null || string.IsNullOrEmpty(adLookupResult.EmployeeId)) { ModelState.AddModelError(string.Empty, "登录尝试无效。"); return Page(); } // 先验证用户密码,不直接登录 var user = await _signInManager.UserManager.FindByNameAsync(Input.Username); if (user == null || !await _signInManager.UserManager.CheckPasswordAsync(user, Input.Password)) { ModelState.AddModelError(string.Empty, "登录尝试无效。"); return Page(); } // 生成用户主体并添加自定义声明 var claimsPrincipal = await _signInManager.CreateUserPrincipalAsync(user); claimsPrincipal.Identities.First().AddClaim(new Claim("EmployeeId", adLookupResult.EmployeeId)); // 手动完成登录 await _signInManager.SignInAsync(user, Input.RememberMe); _logger.LogInformation("用户已登录。"); return LocalRedirect(returnUrl); }
关键说明:
- 替换
PasswordSignInAsync为手动验证密码+生成主体的方式,这样才能在登录前修改ClaimsPrincipal。 - 使用
CreateUserPrincipalAsync获取默认用户主体,在第一个身份标识中添加自定义声明。 - 调用
SignInAsync完成登录,确保包含自定义声明的主体被持久化到Cookie中。
组件中访问声明的正确方式:
在Blazor组件中通过级联参数获取AuthenticationState,再提取声明:
@inject AuthenticationStateProvider AuthenticationStateProvider @code { private string employeeId; protected override async Task OnInitializedAsync() { var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync(); var user = authState.User; employeeId = user.FindFirstValue("EmployeeId"); } }
内容的提问来源于stack exchange,提问作者Ash K
相关产品推荐
相关产品推荐

