MVc Identity登陆锁定
[ASP.NET Identity] OAuth Server 鎖定(Lockout)登入失敗次數太多的帳號
- 743
- 6
- ASP.NET Identity
- 檢舉文章
- 2016-08-04
這個功能看似很簡單,但我一直無法成功鎖定帳號,追根究柢就是不了解運作方式,以下就來分享實作心得
Lockout 相關成員
欄位
帳號失敗次數鎖定,在 AspNetUsers Table 用三個欄位控制
- LockedEnable:是否啟用鎖定
- AccessFailedCount:失敗次數
- LockoutEndDateUtc:鎖定到期時間
行為
- ApplicationUserManager.SetLockoutEnabledAsync(user.Id) 方法,控制 LockedEnable 欄位= true | false
- ApplicationUserManager.AccessFailedAsync(user.Id) 方法,控制 LockoutEndDateUtc 和 AccessFailedCount 欄位。
- ApplicationUserManager.SetLockoutEndDateAsync() 方法,控制結束鎖定時間
- ApplicationUserManager.IsLockedOutAsync(user.Id) ,以 LockoutEndDateUtc 和 LockedEnable 欄位決定是否為 Lockout
另外,ApplicationSignInManager 也能處理 Lockout
- ApplicationSignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: true),
屬性
還有三個屬性,可以定義,分別是:
- ApplicationUserManager.DefaultAccountLockoutTimeSpan 屬性,鎖定時間
- ApplicationUserManager.MaxFailedAccessAttemptsBeforeLockout 屬性,最多失敗次數
- ApplicationUserManager.UserLockoutEnabledByDefault 屬性,建立帳號時是否啟用鎖定
Step1.定義 Lockout 屬性
@Startup.cs
把控制 Lockout 的屬性放在 Startup.CreateUserManager 方法集中建立
@AppSetting.cs
這個類別,提供讀取 Web.Config 的屬性並 Cache 起來,以免一個 Request 請求就讀一次檔案
public class AppSetting
{
private static TimeSpan? s_defaultAccountLockoutTimeSpan;
private static int? s_maxFailedAccessAttemptsBeforeLockout;
private static bool? s_userLockoutEnabledByDefault;
public static TimeSpan DefaultAccountLockoutTimeSpan
{
get
{
if (!s_defaultAccountLockoutTimeSpan.HasValue)
{
double result;
if (double.TryParse(ConfigurationManager.AppSettings["DefaultAccountLockoutTimeSpan"], out result))
{
s_defaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(result);
}
else
{
s_defaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(20);
}
}
return s_defaultAccountLockoutTimeSpan.Value;
}
set { s_defaultAccountLockoutTimeSpan = value; }
}
public static int MaxFailedAccessAttemptsBeforeLockout
{
get
{
if (!s_maxFailedAccessAttemptsBeforeLockout.HasValue)
{
int result;
if (int.TryParse(ConfigurationManager.AppSettings["MaxFailedAccessAttemptsBeforeLockout"],
out result))
{
s_maxFailedAccessAttemptsBeforeLockout = result;
}
else
{
s_maxFailedAccessAttemptsBeforeLockout = 5;
}
s_maxFailedAccessAttemptsBeforeLockout = result;
}
return s_maxFailedAccessAttemptsBeforeLockout.Value;
}
set { s_maxFailedAccessAttemptsBeforeLockout = value; }
}
public static bool UserLockoutEnabledByDefault
{
get
{
if (!s_userLockoutEnabledByDefault.HasValue)
{
bool result;
if (bool.TryParse(ConfigurationManager.AppSettings["UserLockoutEnabledByDefault"], out result))
{
s_userLockoutEnabledByDefault = result;
}
else
{
s_userLockoutEnabledByDefault = true;
}
s_userLockoutEnabledByDefault = result;
}
return s_userLockoutEnabledByDefault.Value;
}
set { s_userLockoutEnabledByDefault = value; }
}
}
Step2.撰寫鎖定邏輯
@AuthorizationServerProvider.cs
在取得 Token 的 GrantResourceOwnerCredentials 方法裡面,控制帳號鎖定邏輯
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
var user = await userManager.FindByNameAsync(context.UserName);
if (user == null)
{
var message = "Invalid credentials. Please try again.";
context.SetError("invalid_grant", message);
return;
}
var validCredentials = await userManager.FindAsync(context.UserName, context.Password);
var enableLockout = await userManager.GetLockoutEnabledAsync(user.Id);
if (await userManager.IsLockedOutAsync(user.Id))
{
var message = string.Format(
"Your account has been locked out for {0} minutes due to multiple failed login attempts.",
AppSetting.DefaultAccountLockoutTimeSpan.TotalMinutes);
;
context.SetError("invalid_grant", message);
return;
}
if (enableLockout & validCredentials == null)
{
string message;
await userManager.AccessFailedAsync(user.Id);
if (await userManager.IsLockedOutAsync(user.Id))
{
message =
string.Format(
"Your account has been locked out for {0} minutes due to multiple failed login attempts.",
AppSetting.DefaultAccountLockoutTimeSpan.TotalMinutes);
}
else
{
var accessFailedCount = await userManager.GetAccessFailedCountAsync(user.Id);
var attemptsLeft = AppSetting.MaxFailedAccessAttemptsBeforeLockout -
accessFailedCount;
message =
string.Format(
"Invalid credentials. You have {0} more attempt(s) before your account gets locked out.",
attemptsLeft);
}
context.SetError("invalid_grant", message);
return;
}
if (validCredentials == null)
{
var message = "Invalid credentials. Please try again.";
context.SetError("invalid_grant", message);
return;
}
await userManager.ResetAccessFailedCountAsync(user.Id);
var oAuthIdentity = await userManager.CreateIdentityAsync(user, OAuthDefaults.AuthenticationType);
var properties = CreateProperties(user.UserName);
var oAuthTicket = new AuthenticationTicket(oAuthIdentity, properties);
context.Validated(oAuthTicket);
}
Step3.撰寫測試程式碼
可以在測試程式碼裡直接注入 Lockout 屬性
[ClassInitialize]
public static void Initialize(TestContext testContext)
{
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<ApplicationDbContext>());
AppSetting.UserLockoutEnabledByDefault = true;
AppSetting.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
AppSetting.MaxFailedAccessAttemptsBeforeLockout = 3;
}
在測試程式碼,我模擬登入失敗超過三次
[TestMethod]
public async Task Login_Fail_3_Lockout_3Test()
{
await RegisterAsync();
Password = "Pass@w0rd2~";
var token1 = await LoginAsync();
token1.ErrorDescription.Should()
.Be("Invalid credentials. You have 2 more attempt(s) before your account gets locked out.");
Password = "Pass@w0rd2~";
var token2 = await LoginAsync();
token2.ErrorDescription.Should()
.Be("Invalid credentials. You have 1 more attempt(s) before your account gets locked out.");
Password = "Pass@w0rd2~";
var token3 = await LoginAsync();
token3.ErrorDescription.Should()
.Be("Your account has been locked out for 5 minutes due to multiple failed login attempts.");
}
MVc Identity登陆锁定的更多相关文章
- Python作业之三次登陆锁定用户
作业之三次登陆锁定用户 作业要求如下: 1. 输入用户名和密码 2. 认证成功提示欢迎信息 3. 认证失败三次锁定用户 具体代码如下: 方法1: import os#导入os模块 if os.path ...
- ASP.NET MVC Identity 兩個多個連接字符串問題解決一例
按照ASP.NET MVC Identity建立了一個用戶權限管理模塊,由于還要加自己已有的數據庫,所以建立了一個實體模型,建立了之后,發現登錄不了: 一直顯示“Login in failed for ...
- MVC绕过登陆界面验证时HttpContext.Current.User.Identity.Name取值为空问题解决方法
Global.asax界面添加如下方法: void FormsAuthentication_Authenticate(object sender, FormsAuthenticationEventAr ...
- MVC SSO登陆 的麻烦事~
前段时间用MVC + Redis 做session搞了个简单的单点登录Web站.真是日了狗的问题多. 今天正好睡不着,做个备忘笔记>_< 实现方法很简单,无非就是从重载个Controlle ...
- MVC用户登陆验证及权限检查(Form认证)
1.配置Web.conf,使用Form认证方式 <system.web> <authentication mode="None" /> ...
- MVC基本登陆与验证码功能实现
一.基本登陆实现与验证码功能实现,该功能是和spring.net功能集合使用的,因为后面要用到验证是否处于登陆状态 1. 先构建一个登陆页面 @{ Layout = null; } <!DOCT ...
- .NET MVC中登陆授权过滤器的使用
1.写个类LoginAuthorityAttribute,继承自AuthorizeAttribute using System; using System.Collections.Generic; u ...
- [Python3.x]多次登陆锁定用户
要求:输入用户名,密码认证成功显示欢迎信息输入错误三次后锁定用户Readme: 1.account.txt是存放用户id及密码的文件 2.account_loc.txt是存放被锁定的用户id的文档,默 ...
- ASP.NET MVC Identity 添加角色
using Microsoft.AspNet.Identity; public ActionResult AddRole(String name){ using (var roleManager = ...
随机推荐
- ubuntu去除带锁文件的锁 sudo chown 用户名 目标文件夹/ -R
sudo chown 用户名 目标文件夹/ -R sudo chown han dir/ -R
- LINUX系统一一常用命令
前言 LINUX UNIX Centos RedHat Ubuntu SHELL shell脚本 shell shell命令 类似windows系统的bat 批处理文件 里面都是脚本 CentOS6. ...
- listview点击checkbox,修改值
1.初始化控件 listView1.Items.Clear(); listView1.Columns.Clear(); ColumnHeader ch = ...
- unity 随笔
转载 慕容小匹夫 从游戏脚本语言说起,剖析Mono所搭建的脚本基础 深入浅出聊优化:从Draw Calls到GC 谁偷了我的热更新?Mono,JIT,IOS JS or C ...
- unity 三种注入示例
/* * 演示Unity 注入 * */ using Microsoft.Practices.Unity; using System; namespace Unity.Property.Inject ...
- 吴裕雄 python神经网络 手写数字图片识别(5)
import kerasimport matplotlib.pyplot as pltfrom keras.models import Sequentialfrom keras.layers impo ...
- HDU 6351 Naive Operations(线段树)
题目: http://acm.hdu.edu.cn/showproblem.php?pid=6315 Naive Operations Time Limit: 6000/3000 MS (Java/O ...
- stevedore动态加载模块
stevedore动态加载模块,stevedore使用setuptools的entry points来定义并加载插件.entry point引用的是定义在模块中的对象,比如类.函数.实例等,只要在im ...
- Android 性能测试之内存 --- 追加腾讯性能案例,安卓抓取性能扫盲帖
内存测试: 思路 目前做的是酒店APP,另下载安装几个个第三方酒店的APP以方便对比(相当于可以做竞品测试) 数据的获取来源是ADB底层命令,而且最好是不需要root权限,因为很多手机root很麻烦或 ...
- c# 记录内容到txt文件
string a= content;//采样结果 if (!File.Exists("e:\\newfile\\newtxt.txt")) { new FileStream(&qu ...