Suggested Videos
Part 120 - ASP.NET Core encryption and decryption example | Text | Slides
Part 121 - Change password in asp.net core | Text | Slides
Part 122 - Add password to local account linked to external login | Text | Slides
In this video we will discuss how to implement user account lockout in asp.net core.
What is account lockout
Account lockout is locking (i.e disabling) the account after too many failed logon attempts. Most banks lock the account after 5 failed attempts. After how many failed attempts, should the account be locked out, depends on the lockout policy of the company. The number of failed attempts after which an account should be locked is configurable in asp.net core.
Why should we lock accounts
Account lockout is to prevent attackers from brute-force attempts to guess a user's password. After certain number of failed logon attempts the account will be temporarily locked for a specified amount of time. How long the account should be locked is again configurable and we will see this in action in just a bit.
Let's say we lock the account for 15 minutes after 5 failed logon attempts. After 15 minutes the user will get another 5 attempts to logon. After 5 failed attempts the account will be locked for another 15 minutes. So this means, it will take many years for an attacker to successfully crack the password.
An organisation may also have password change policy, meaning the password must be changed every 1 or 2 months. So account lockout policy combined with password change policy makes it extremely difficult for an attacker to brute-force (i.e guess) password and gain access.
Configure account lockout options in asp.net core
Account lockout options are configured in ConfigureServices() method of the Startup class.
MaxFailedAccessAttempts - Specifies the number of failed logon attempts allowed before the account is locked out. The default is 5.
DefaultLockoutTimeSpan - Specifies the amount of the time the account should be locked. The default it 5 minutes.
Enable account lockout
Modify the code in Login() action in AccountController to enable account lockout. The code is commented where required.
Account Locked View
After the account is locked, there are 2 options. Wait for the account lockout time to expire which in our case is 15 minutes and then try again or request password reset if you have forgotten the password.
Set lockout end date on successful password reset
If the user is lockedout, password reset can be requested. Upon successful password reset, set the account lockout end date to current UTC date time, so the user can login with the new password. Use SetLockoutEndDateAsync() method of the UserManager service for this.
Part 120 - ASP.NET Core encryption and decryption example | Text | Slides
Part 121 - Change password in asp.net core | Text | Slides
Part 122 - Add password to local account linked to external login | Text | Slides
In this video we will discuss how to implement user account lockout in asp.net core.
What is account lockout
Account lockout is locking (i.e disabling) the account after too many failed logon attempts. Most banks lock the account after 5 failed attempts. After how many failed attempts, should the account be locked out, depends on the lockout policy of the company. The number of failed attempts after which an account should be locked is configurable in asp.net core.
Why should we lock accounts
Account lockout is to prevent attackers from brute-force attempts to guess a user's password. After certain number of failed logon attempts the account will be temporarily locked for a specified amount of time. How long the account should be locked is again configurable and we will see this in action in just a bit.
Let's say we lock the account for 15 minutes after 5 failed logon attempts. After 15 minutes the user will get another 5 attempts to logon. After 5 failed attempts the account will be locked for another 15 minutes. So this means, it will take many years for an attacker to successfully crack the password.
An organisation may also have password change policy, meaning the password must be changed every 1 or 2 months. So account lockout policy combined with password change policy makes it extremely difficult for an attacker to brute-force (i.e guess) password and gain access.
Configure account lockout options in asp.net core
Account lockout options are configured in ConfigureServices() method of the Startup class.
MaxFailedAccessAttempts - Specifies the number of failed logon attempts allowed before the account is locked out. The default is 5.
DefaultLockoutTimeSpan - Specifies the amount of the time the account should be locked. The default it 5 minutes.
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
options.Lockout.MaxFailedAccessAttempts = 5;
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(15);
});
// Rest of the code
}
{
services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
options.Lockout.MaxFailedAccessAttempts = 5;
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(15);
});
// Rest of the code
}
Enable account lockout
Modify the code in Login() action in AccountController to enable account lockout. The code is commented where required.
[HttpPost]
[AllowAnonymous]
public async
Task<IActionResult> Login(LoginViewModel model, string returnUrl)
{
model.ExternalLogins =
(await signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
if (ModelState.IsValid)
{
var user = await
userManager.FindByEmailAsync(model.Email);
if (user != null
&& !user.EmailConfirmed &&
(await userManager.CheckPasswordAsync(user, model.Password)))
{
ModelState.AddModelError(string.Empty, "Email not confirmed yet");
return View(model);
}
// The last
boolean parameter lockoutOnFailure indicates if the account
// should be
locked on failed logon attempt. On every failed logon
// attempt
AccessFailedCount column value in AspNetUsers table is
// incremented by
1. When the AccessFailedCount reaches the configured
//
MaxFailedAccessAttempts which in our case is 5, the account will be
// locked and
LockoutEnd column is populated. After the account is
// lockedout,
even if we provide the correct username and password,
//
PasswordSignInAsync() method returns Lockedout result and the login
// will not be
allowed for the duration the account is locked.
var result = await
signInManager.PasswordSignInAsync(model.Email,
model.Password, model.RememberMe, true);
if (result.Succeeded)
{
if (!string.IsNullOrEmpty(returnUrl)
&& Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("index", "home");
}
}
// If account
is lockedout send the use to AccountLocked view
if (result.IsLockedOut)
{
return View("AccountLocked");
}
ModelState.AddModelError(string.Empty, "Invalid Login Attempt");
}
return View(model);
}
Account Locked View
After the account is locked, there are 2 options. Wait for the account lockout time to expire which in our case is 15 minutes and then try again or request password reset if you have forgotten the password.
<h3 class="text-danger">
Your account is locked, please try again
after sometime or you may
<a asp-action="ForgotPassword" asp-controller="Account">
reset your password by clicking here
</a>
</h3>
Set lockout end date on successful password reset
If the user is lockedout, password reset can be requested. Upon successful password reset, set the account lockout end date to current UTC date time, so the user can login with the new password. Use SetLockoutEndDateAsync() method of the UserManager service for this.
[HttpPost]
[AllowAnonymous]
public async
Task<IActionResult> ResetPassword(ResetPasswordViewModel model)
{
if (ModelState.IsValid)
{
var user = await
userManager.FindByEmailAsync(model.Email);
if (user != null)
{
var result =
await userManager.ResetPasswordAsync(user, model.Token,
model.Password);
if (result.Succeeded)
{
// Upon
successful password reset and if the account is lockedout, set
// the
account lockout end date to current UTC date time, so the user
// can
login with the new password
if (await
userManager.IsLockedOutAsync(user))
{
await
userManager.SetLockoutEndDateAsync(user, DateTimeOffset.UtcNow);
}
return View("ResetPasswordConfirmation");
}
foreach (var error in result.Errors)
{
ModelState.AddModelError("", error.Description);
}
return View(model);
}
return View("ResetPasswordConfirmation");
}
return View(model);
}
These are missing from this text:
ReplyDelete[HttpGet]
[AllowAnonymous]
public IActionResult ForgotPassword()
{
return View();
}
----
ResetPasswordViewModel
ResetPassword.cshtml
&
ResetPasswordConfirmation.cshtml