我正在尝试通过在数据库中添加逻辑“已删除”列来扩展身份用户.
然后,我想使用此值使用自定义UserClaimsPrincipalFactory向用户添加声明.
我想在登录时检查“已删除”声明,如果用户的帐户已删除,则拒绝该用户.
问题:当我尝试通过User.Clams访问声明时,用户没有声明.
唯一可以使它起作用的方法是覆盖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是Claimsprincipal,但未通过身份验证,在调用SignIn的代码之前以及在您的Claimsprincipal工厂方法被调用之前,auth中间件从请求中反序列化了该User.
signin方法确实创建了新的经过身份验证的Claimsprincipal,并且应该将其序列化到auth cookie中,因此在下一个请求时,将从cookie中反序列化User并对其进行身份验证,但是对于当前请求已经发生了反序列化.因此,针对当前请求更改它的唯一方法是,如您所知,在当前httpcontext上重置User.
我认为最好以不同的方式拒绝用户,而不是在成功登录后拒绝用户,最好是在较低级别上检查并让登录失败,而不是先成功然后退出.我在自定义用户存储区的项目中做到了这一点.