【问题标题】:How to disable a User in Identity 2.0?如何在 Identity 2.0 中禁用用户?
【发布时间】:2015-10-05 14:37:27
【问题描述】:

我正在尝试找到一种方法来禁用 Identity 2.0 中的用户,但似乎找不到任何信息。

我想基本上将用户设置为 IsActive=false,并且希望在创建用户后立即执行此操作。但是,我需要一种方法来为我们的站点管理员设置 IsActive。我已经拥有 ASP.Net 成员资格,但我希望将站点转换为 MVC 和 Identity。

根据我的要求,我们要求人们继续注册一个帐户,但我们希望它默认禁用。然后,当我们收到加入的付款时,我们将返回并启用它们。我们还使用它来禁用订阅已到期且尚未续订的用户。

有没有办法在不删除帐户的情况下禁用帐户或仅将其锁定 X 时间?到目前为止,我还没有找到任何方法来禁用 Identity 中的用户,我很惊讶这个问题以前没有出现过。

【问题讨论】:

    标签: c# asp.net asp.net-identity asp.net-identity-2


    【解决方案1】:

    当您创建安装了身份位的站点时,您的站点将有一个名为“IdentityModels.cs”的文件。在这个文件中有一个名为 ApplicationUser 的类,它继承自 IdentityUser。

    // You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
    public class ApplicationUser : IdentityUser
    

    那里的cmets中有一个不错的链接,为方便点击here

    本教程准确地告诉您为您的用户添加自定义属性需要做什么。

    实际上,甚至不必费心看教程。

    1) 给ApplicationUser类添加一个属性,例如:

    public bool? IsEnabled { get; set; }
    

    2) 在数据库的 AspNetUsers 表中添加同名列。

    3) 繁荣,就是这样!

    现在在您的 AccountController 中,您有一个注册操作,如下所示:

    public async Task<ActionResult> Register(RegisterViewModel model)
            {
                if (ModelState.IsValid)
                {
                    var user = new ApplicationUser { UserName = model.Email, Email = model.Email, IsEnabled = true };
                    var result = await UserManager.CreateAsync(user, model.Password);
                    if (result.Succeeded)
    

    我在创建 ApplicationUser 对象时添加了 IsEnabled = true。该值现在将保留在 AspNetUsers 表的新列中。

    然后,您需要通过覆盖 ApplicationSignInManager 中的 PasswordSignInAsync 来处理检查此值作为登录过程的一部分。

    我是这样做的:

    public override Task<SignInStatus> PasswordSignInAsync(string userName, string password, bool rememberMe, bool shouldLockout)
        {
            var user = UserManager.FindByEmailAsync(userName).Result;
    
            if ((user.IsEnabled.HasValue && !user.IsEnabled.Value) || !user.IsEnabled.HasValue)
            {
                return Task.FromResult<SignInStatus>(SignInStatus.LockedOut);
            }
    
            return base.PasswordSignInAsync(userName, password, rememberMe, shouldLockout);
        }
    

    您的里程可能会有所不同,您可能不想返回该 SignInStatus,但您明白了。

    【讨论】:

    • 如何在 ASP.NET Core 1.0 中使用没有 ApplicationSignInManager 或 PasswordSignInAsync(...) 的 Identity 3.0 实现相同的功能?
    • 使用.Result 是违反建议的,并且已知会在某些情况下导致死锁,它还会阻止线程破坏整个异步点。最好将PasswordSignInAsync 方法标记为async 并改为等待FindByEmailAsync
    • 最大的问题是如果他们已经登录了,它不会影响他们。特别是如果他们选中了记住我复选框。如果他们定期访问该站点,他们将永远不需要登录。我试图弄清楚现有的锁定逻辑是否可以用于此,以及它是否更好地处理已经登录的用户.
    【解决方案2】:

    对此进行了一些研究,结果发现IdentityUser 基类具有与该主题相关的一些属性。即:LockoutEnabledLockoutEndDateUtc

    LockoutEnabled 设置为trueLockoutEndDateUtc 就足够了,以使标准SignInManager.PasswordSignInAsync 能够在不进行任何覆盖或自定义的情况下进行相应操作。

    如果您只想禁用用户而不指定任何确切的重新激活日期,您可以将其设置为DateTime.MaxValue

    【讨论】:

    • 令人困惑的是,文档说“获取或设置一个标志,指示用户是否可以被锁定。”;为什么“可以”?嗯
    【解决方案3】:

    第 1 步:创建一个实现 IUserLockoutStore 的自定义用户存储。

         public Task<DateTimeOffset> GetLockoutEndDateAsync(MyUser user)
        {
            //..
        }
    
        public Task SetLockoutEndDateAsync(MyUser user, DateTimeOffset lockoutEnd)
        {
            //..
        }
    
        public Task<int> IncrementAccessFailedCountAsync(MyUser user)
        {
            //..
        }
    
        public Task ResetAccessFailedCountAsync(MyUser user)
        {
            //..
        }
    
        public Task<int> GetAccessFailedCountAsync(MyUser user)
        {
            //..
        }
    
        public Task<bool> GetLockoutEnabledAsync(MyUser user)
        {
            //..
        }
    
        public Task SetLockoutEnabledAsync(MyUser user, bool enabled)
        {
            //..
        }
    }
    

    第 2 步:在登录/注销操作中使用以下类,而不是 UserManager,将自定义用户存储的实例传递给它。

        public class LockingUserManager<TUser, TKey> : UserManager<TUser, TKey>
        where TUser : class, IUser<TKey> 
        where TKey : IEquatable<TKey> 
    {
        private readonly IUserLockoutStore<TUser, TKey> _userLockoutStore;
    
        public LockingUserManager(IUserLockoutStore<TUser, TKey> store)
            : base(store)
        {
            if (store == null) throw new ArgumentNullException("store");
    
            _userLockoutStore = store;
        }
    
        public override async Task<TUser> FindAsync(string userName, string password)
        {
            var user = await FindByNameAsync(userName);
    
            if (user == null) return null;
    
            var isUserLockedOut = await GetLockoutEnabled(user);
    
            if (isUserLockedOut) return user;
    
            var isPasswordValid = await CheckPasswordAsync(user, password);
    
            if (isPasswordValid)
            {
                await _userLockoutStore.ResetAccessFailedCountAsync(user);
            }
            else
            {
                await IncrementAccessFailedCount(user);
    
                user = null;
            }
    
            return user;
        }
    
        private async Task<bool> GetLockoutEnabled(TUser user)
        {
            var isLockoutEnabled = await _userLockoutStore.GetLockoutEnabledAsync(user);
    
            if (isLockoutEnabled == false) return false;
    
            var shouldRemoveLockout = DateTime.Now >= await _userLockoutStore.GetLockoutEndDateAsync(user);
    
            if (shouldRemoveLockout)
            {
                await _userLockoutStore.ResetAccessFailedCountAsync(user);
    
                await _userLockoutStore.SetLockoutEnabledAsync(user, false);
    
                return false;
            }
    
            return true;
        }
    
        private async Task IncrementAccessFailedCount(TUser user)
        {
            var accessFailedCount = await _userLockoutStore.IncrementAccessFailedCountAsync(user);
    
            var shouldLockoutUser = accessFailedCount > MaxFailedAccessAttemptsBeforeLockout;
    
            if (shouldLockoutUser)
            {
                await _userLockoutStore.SetLockoutEnabledAsync(user, true);
    
                var lockoutEndDate = new DateTimeOffset(DateTime.Now + DefaultAccountLockoutTimeSpan);
    
                await _userLockoutStore.SetLockoutEndDateAsync(user, lockoutEndDate);
            }
        }
    }
    

    示例

     [AllowAnonymous]
        [HttpPost]
        public async Task<ActionResult> Login(string userName, string password)
        {
            var userManager = new LockingUserManager<MyUser, int>(new MyUserStore())
            {
                DefaultAccountLockoutTimeSpan = /* get from appSettings */,
                MaxFailedAccessAttemptsBeforeLockout = /* get from appSettings */
            };
    
            var user = await userManager.FindAsync(userName, password);
    
            if (user == null)
            {
                // bad username or password; take appropriate action
            }
    
            if (await _userManager.GetLockoutEnabledAsync(user.Id))
            {
                // user is locked out; take appropriate action
            }
    
            // username and password are good
            // mark user as authenticated and redirect to post-login landing page
        }
    

    Source

    【讨论】:

    • 我可能对此感到困惑,或者它没有解决问题。我从代码中获取的内容将用于查看用户是否处于锁定状态,这将来自不成功的登录尝试。看起来它只设置了注销时间和锁定失败登录尝试的次数。我正在寻找是否可以禁用该帐户。执行设置 IsActive=false 之类的操作。这样他们就无法登录。当更新发生时,我只需重置 IsActive=true。类似的东西。我仍然会更多地查看代码,看看它是否可以工作。
    • 我想抛出一个我将尝试实施以禁用用户的想法。我将创建一个名为“NoAccess”的角色。然后在我的控制器上,我不会将该角色包含为可以访问任何 ActionResult 的角色。就我而言,当有人注册时,我将使用它作为我的默认角色。我认为这会满足我的需求。
    • 但是,看起来我可能不得不在某些登录失败后不将身份设置为锁定,或者使用上面的代码。我很惊讶微软没有让查看某人被锁定和/或更简单的解锁方法变得更容易。
    猜你喜欢
    • 1970-01-01
    • 2014-05-15
    • 2016-01-02
    • 2014-06-28
    • 1970-01-01
    • 2014-05-02
    • 1970-01-01
    • 2014-06-01
    • 1970-01-01
    相关资源
    最近更新 更多