[英]Role based claims in Identity Server 3 + AspNet Identity
[英]AspNet Identity Core - Custom Claims on Login
我正在嘗試通過在數據庫中添加一個邏輯“已刪除”列來擴展我的身份用戶。
然后,我想使用此值向使用自定義 UserClaimsPrincipalFactory 的用戶添加聲明。
我想在登錄時檢查“已刪除”聲明,如果用戶的帳戶已被刪除,則拒絕該用戶。
問題:當我嘗試通過 User.Claims 訪問聲明時,用戶沒有聲明。
我唯一可以使它工作的是通過覆蓋 httpcontext 用戶
public class ApplicationClaimsIdentityFactory : UserClaimsPrincipalFactory<ApplicationUser, IdentityRole>
{
private readonly IHttpContextAccessor _httpContext;
public ApplicationClaimsIdentityFactory(UserManager<ApplicationUser> userManager, RoleManager<IdentityRole> roleManager, IOptions<IdentityOptions> options, IHttpContextAccessor httpContext) : base(userManager, roleManager, options)
{
_httpContext = httpContext;
}
public override async Task<ClaimsPrincipal> CreateAsync(ApplicationUser user)
{
ClaimsPrincipal principal = await base.CreateAsync(user);
ClaimsIdentity claimsIdentity = (ClaimsIdentity) principal.Identity;
claimsIdentity.AddClaim(new Claim("Deleted", user.Deleted.ToString().ToLower()));
//I DON'T WANT TO HAVE TO DO THIS
_httpContext.HttpContext.User = principal;
return principal;
}
}
登錄操作:
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
{
SignInResult result = await _signInManager.PasswordSignInAsync(model.Email, model.Password,
model.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
//No claims exists at this point unless I force the HttpContext user (See above)
if (User.Claims.First(x => x.Type == "Deleted").Value.Equals("true", StringComparison.CurrentCultureIgnoreCase);)
{
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
await _signInManager.SignOutAsync();
return View(model);
}
.... Continue login code...
我的 ApplicationUser 類
public class ApplicationUser : IdentityUser
{
public bool Deleted { get; set; }
}
最后我的啟動注冊
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<DbContext>()
.AddClaimsPrincipalFactory<ApplicationClaimsIdentityFactory>()
.AddDefaultTokenProviders();
謝謝
我認為問題在於您試圖在發布登錄操作時在一個請求中完成所有操作。
您在該方法中擁有的 User 是一個 claimprincipal 但未經過身份驗證,在調用 SignIn 的代碼之前和調用您的 claimprincipal 工廠方法之前,auth 中間件將其從請求中反序列化。
signin 方法確實創建了新的經過身份驗證的 claimprincipal 並且應該將其序列化到 auth cookie 中,因此在下一個請求中,用戶將從 cookie 中反序列化並進行身份驗證,但是當前請求已經發生了反序列化。 因此,為當前請求更改它的唯一方法是在您找到的當前 httpcontext 上重置用戶。
我認為最好不要在登錄成功后以不同的方式拒絕用戶,最好在較低級別進行檢查並使登錄失敗,而不是成功然后注銷。 我在自定義用戶存儲的項目中執行此操作。
聲明在 PasswordSignInAsync 方法之后不可用。 您可以使用它在構造函數中添加 UserManager 的一種解決方法,例如:
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly ILogger<LoginModel> _logger;
private readonly UserManager<ApplicationUser> _userManager; //<----here
public LoginModel(SignInManager<ApplicationUser> signInManager,
UserManager<ApplicationUser> userManager, //<----here
ILogger<LoginModel> logger)
{
_signInManager = signInManager;
_userManager = userManager;//<----here
_logger = logger;
}
在 Login 方法中,您可以檢查 IsDeleted 屬性,例如:
var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: true);
if (result.Succeeded)
{
var user = await _userManager.FindByNameAsync(Input.Email); //<----here
if (user.IsDeleted) //<----here
{
ModelState.AddModelError(string.Empty, "This user doesn't exist.");
await _signInManager.SignOutAsync();
return Page();
}
_logger.LogInformation("User logged in.");
return LocalRedirect(returnUrl);
}
這是我的第一個堆棧溢出答案:)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.