AspNet Identity Core - 自定义登录声明

问题描述 投票:0回答:3

我试图通过在数据库中添加逻辑“已删除”列来扩展我的身份用户。

然后我想使用此值通过自定义 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();

谢谢

c# asp.net-core identity claims-based-identity
3个回答
3
投票

我认为问题是您在发布登录操作时试图在一个请求中完成所有操作。

您在该方法中拥有的用户是一个 ClaimsPrincipal,但未经过身份验证,在调用 SignIn 代码之前以及调用您的 ClaimsPrincipal 工厂方法之前,它是由身份验证中间件从请求中反序列化的。

登录方法确实创建了新的经过身份验证的声明主体,并且应该将其序列化到身份验证 cookie 中,因此在下一个请求中,用户将从 cookie 中反序列化并进行身份验证,但当前请求已经发生了反序列化。因此,为当前请求更改它的唯一方法是在当前 httpcontext 上重置用户,正如您所发现的那样。

我认为最好在登录成功后以不同的方式拒绝用户,最好在较低级别进行检查并使登录失败,而不是成功然后注销。我在我的项目中的自定义用户存储中执行了此操作。


1
投票

在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);
            }

这是我的第一个堆栈溢出答案:)


0
投票

//使用这两种方式之一。我测试了这些。

//将“IHttpContextAccessor httpContext”添加到您的 UserClaimsPrincipalFactory 构造函数中。

//然后将您的自定义声明添加到 _httpContext : _httpContext.HttpContext.User.AddIdentity(claimsIdentity);

//完成。

//同时您可以通过以下方式为 Items["harchi"] 设置值: _httpContext.HttpContext.Items["enything"] = 值;

//然后使用这个: HttpContext.Items["harchi"];

© www.soinside.com 2019 - 2024. All rights reserved.