I’ve spent a few hours trying to figure out why my code does not work, and I have not found any explanations to the issue, so might just write it down here.
In ASP.NET Identity there is a concept for user locking out. You can specify how many attempts user can gets before the lock-out kicks in and for how long the lockout is enabled. This is a widely known, from all the articles online. But what these articles don’t say is that users can be opted-in and opted-out from this process.
If you look on
IdentityUser class, there are 2 fields that relate to lockout:
LockoutEndDateUtc. My first reaction was that
LockoutEnabled says that user is locked-out and
LockoutEndDateUtc is time when the lockout expires.
Turned out that I was wrong.
LockoutEnabled is a flag saying that user can (or can not) be locked in principle. I.e. opt-in flag for locking. So if we have an admin user who we don’t want to lockout ever, we’ll set this flag to be
false. And for the rest of user-base this should be set to
To check if user is locked-out use
UserManager.GetLockoutEnabledAsync() checks if user is opted in for lock-out, it does not check if user is actually locked-out.
And fields on
IdentityUser – don’t use them to detect is user is locked out, they are lies! Use UserManager functions to detect user state.
Hope this will save some people a head-banging, cause that caused me some stress!
Update 27 Aug 2014
To enable locking-out UserManager should have these flags set:
//lockout users for 10 minutes UserManager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(10); // takes 6 incorrect attempts to lockout this.MaxFailedAccessAttemptsBeforeLockout = 6; // when new user is created, they will be "lockable". this.UserLockoutEnabledByDefault = true;
To lockout user you can do this:
user.LockoutEnabled = true; user.LockoutEndDateUtc = DateTime.UtcNow.AddMinutes(42); await userManager.UpdateAsync(user);
This will set the user to be locked out for 42 minutes from now. However, this is not recommended way to lock-out user, this is what the framework does in the background. There are ways users can lock themselves out.
If you are updated to AspNet Identity 2.1 (which has been released recently). You should use
var signInManager = new SignInManager(userManager, authenticationManager); var signInStatus = await signInManager.PasswordSignInAsync(username, password, isPersistent, shouldLockout);
shouldLockout is true, user is getting locked out after a number of failed attempts to login.
PasswordSignInAsync method does the following steps:
- checks if user with given username exists;
- then checks if this user is not locked out;
- if password is correct, redirects logic to 2FA (if it is enabled);
shouldLockoutis true, then on incorrect password increases number of failed log-ins on user record.
If you have not updated and still using Identity v2.0 do the following. On every failed attempt to login, call the following
IdentityUser class have property
AccessFailedCount. The method above increases count on this property. If count is greater than
UserManager.MaxFailedAccessAttemptsBeforeLockout, then user is getting locked out:
user.LockoutEndDateUtc is set to a date in the future and resets
AccessFailedCount to zero.
When user is signed-in successfully, you need to reset
AccessFailedCount to zero. Do it by calling: