如何覆盖 ASP.NET Core Identity 的密码策略
Posted
技术标签:
【中文标题】如何覆盖 ASP.NET Core Identity 的密码策略【英文标题】:How override ASP.NET Core Identity's password policy 【发布时间】:2017-02-11 01:05:41 【问题描述】:默认情况下,ASP.NET Core Identity 的密码策略要求至少有一个特殊字符、一个大写字母、一个数字……
如何更改此限制?
文档中对此一无所知 (https://docs.asp.net/en/latest/security/authentication/identity.html)
我尝试覆盖身份的用户管理器,但我没有看到管理密码策略的方法。
public class ApplicationUserManager : UserManager<ApplicationUser>
public ApplicationUserManager(
DbContextOptions<SecurityDbContext> options,
IServiceProvider services,
IHttpContextAccessor contextAccessor,
ILogger<UserManager<ApplicationUser>> logger)
: base(
new UserStore<ApplicationUser>(new SecurityDbContext(contextAccessor)),
new CustomOptions(),
new PasswordHasher<ApplicationUser>(),
new UserValidator<ApplicationUser>[] new UserValidator<ApplicationUser>() ,
new PasswordValidator[] new PasswordValidator() ,
new UpperInvariantLookupNormalizer(),
new IdentityErrorDescriber(),
services,
logger
// , contextAccessor
)
public class PasswordValidator : IPasswordValidator<ApplicationUser>
public Task<IdentityResult> ValidateAsync(UserManager<ApplicationUser> manager, ApplicationUser user, string password)
return Task.Run(() =>
if (password.Length >= 4) return IdentityResult.Success;
else return IdentityResult.Failed(new IdentityError Code = "SHORTPASSWORD", Description = "Password too short" );
);
public class CustomOptions : IOptions<IdentityOptions>
public IdentityOptions Value get; private set;
public CustomOptions()
Value = new IdentityOptions
ClaimsIdentity = new ClaimsIdentityOptions(),
Cookies = new IdentityCookieOptions(),
Lockout = new LockoutOptions(),
Password = null,
User = new UserOptions(),
SignIn = new SignInOptions(),
Tokens = new TokenOptions()
;
我在启动类中添加了这个用户管理器依赖:
services.AddScoped<ApplicationUserManager>();
但是当我在控制器中使用 ApplicationUserManager 时,出现错误: 处理请求时发生未处理的异常。
InvalidOperationException:尝试激活“ApplicationUserManager”时,无法解析“Microsoft.EntityFrameworkCore.DbContextOptions`1[SecurityDbContext]”类型的服务。
编辑:当我使用 ASP.NET Core Identity 的默认类时,用户的管理工作正常,所以这不是数据库问题,或类似的问题
编辑 2:我找到了解决方案,您只需在启动类中配置 Identity。我的回答提供了一些细节。
【问题讨论】:
有趣的事实:MS 强加的默认设置对于 chrome 密码管理器生成的密码来说太严格了。 【参考方案1】:最后太简单了……
无需覆盖任何类,您只需在启动类中配置身份设置,如下所示:
services.Configure<IdentityOptions>(options =>
options.Password.RequireDigit = false;
options.Password.RequiredLength = 5;
options.Password.RequireLowercase = true;
options.Password.RequireNonLetterOrDigit = true;
options.Password.RequireUppercase = false;
);
或者你可以在添加的时候配置身份:
services.AddIdentity<ApplicationUser, IdentityRole>(options=>
options.Password.RequireDigit = false;
options.Password.RequiredLength = 4;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.Password.RequireLowercase = false;
)
.AddEntityFrameworkStores<SecurityDbContext>()
.AddDefaultTokenProviders();
AS.NET Core 绝对是好东西 ...
【讨论】:
解决方案添加到官方文档docs.asp.net/en/latest/security/authentication/identity.html 应用您的解决方案,看起来在 ASP .Net Core 中选项options.Password.RequireNonAlphanumeric = false;
已被弃用并分为 2 个“子选项”:options.Password.RequireDigit = false;
和 options.Password.RequireNonAlphanumeric = false;
。
有趣,我想允许调试时密码长度为 1,但 options.Password.RequiredLength = 1;不起作用(尝试了上述两种情况)。验证仍然需要 6 个字符。其他选项确实有效。
这不起作用。我将顶部添加到 startup.cs 中的 ConfigureServices 方法的底部,我将 RequiredLength 设置为 1,但错误仍然指出它必须在 6 到 100 个字符之间。 (.net 核心 3.2)
RequiredLength github.com/dotnet/aspnetcore/blob/…。如果您可以通过它,它似乎确实尊重其他设置。例如,如果您将 RequiredLength 设置为 7 并且只输入 6 个字符,它将通过该字段的最少 6 个检查,然后在您点击注册按钮时失败并显示“需要 7”。【参考方案2】:
您可以在 IdentityConfig.cs 文件中修改这些规则。 规则在
中定义public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
// Configure validation logic for usernames
manager.UserValidator = new UserValidator<ApplicationUser>(manager)
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
;
// Configure validation logic for passwords
manager.PasswordValidator = new PasswordValidator
RequiredLength = 5,
RequireNonLetterOrDigit = false,
RequireDigit = true,
RequireLowercase = true,
RequireUppercase = true,
;
【讨论】:
【参考方案3】:附加要求:
如果你觉得这个密码限制还不够,你可以定义你的 通过继承自己的条件 PasswordValidator 类。
示例实现:
public class CustomPasswordPolicy : PasswordValidator<AppUser>
public override async Task<IdentityResult> ValidateAsync(UserManager<AppUser> manager, AppUser user, string password)
IdentityResult result = await base.ValidateAsync(manager, user, password);
List<IdentityError> errors = result.Succeeded ? new List<IdentityError>() : result.Errors.ToList();
if (password.ToLower().Contains(user.UserName.ToLower()))
errors.Add(new IdentityError
Description = "Password cannot contain username"
);
if (password.Contains("123"))
errors.Add(new IdentityError
Description = "Password cannot contain 123 numeric sequence"
);
return errors.Count == 0 ? IdentityResult.Success : IdentityResult.Failed(errors.ToArray());
我已经在我的类中重写了 ValidateAsync 方法,并且在这个方法中我正在实现我的自定义密码策略。
非常非常重要
ValidateAsync() 中的第一行代码IdentityResult result = await base.ValidateAsync(manager, user, password);
:
根据 Statup 类的 ConfigureServices 方法中给出的密码规则验证密码(本文旧答案中显示的规则)
密码验证功能由 Microsoft.AspNetCore.Identity 命名空间中的 IPasswordValidator 接口。所以我需要将我的“CustomPasswordPolicy”类注册为“AppUser”对象的密码验证器。 services.AddTransient<IPasswordValidator<AppUser>, CustomPasswordPolicy>();
services.AddDbContext<AppIdentityDbContext>(options => options.UseSqlServer(Configuration["ConnectionStrings:DefaultConnection"]));
services.AddIdentity<AppUser, IdentityRole>(opts =>
opts.Password.RequiredLength = 8;
opts.Password.RequireNonAlphanumeric = true;
opts.Password.RequireLowercase = false;
opts.Password.RequireUppercase = true;
opts.Password.RequireDigit = true;
).AddEntityFrameworkStores<AppIdentityDbContext>().AddDefaultTokenProviders();
PasswordValidator.cs 的官方 Github 文档(为了更好 理解):here
【讨论】:
您好,注册时还没有关联用户怎么办?【参考方案4】:开发人员最简单的方法是
services.AddDefaultIdentity<IdentityUser>(options =>
options.SignIn.RequireConfirmedAccount = true;
options.Password.RequireDigit = false;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.Password.RequireLowercase = false;
)
.AddEntityFrameworkStores<ApplicationDbContext>();
只有Password.RequiredLength不能这样改,还是等于6。
【讨论】:
【参考方案5】:将以下行添加到 startup.cs 的 ConfigureServices 方法中
services.Configure<IdentityOptions>(Configuration.GetSection(nameof(IdentityOptions)));
如果需要,您可以使用不同的部分名称
然后将设置添加到 config.您可以在多个配置源中添加多个设置,它们将被合并。 例如。我把它放在我的 appsettings.local.json 文件中。此文件被 VCS 忽略,因此我的本地设置永远不会生效,这与硬编码设置并使用 #if debug 或类似的东西不同。
"IdentityOptions":
"Password":
"RequiredLength": 6,
"RequireDigit": false,
"RequiredUniqueChars": 1,
"RequireLowercase": false,
"RequireNonAlphanumeric": false,
"RequireUppercase": false
这同样适用于 appsettings.Environment.json 或任何其他配置源,因此您可以在开发服务器和实时服务器上进行不同的设置,而无需更改代码或使用不同的构建配置
【讨论】:
以上是关于如何覆盖 ASP.NET Core Identity 的密码策略的主要内容,如果未能解决你的问题,请参考以下文章
如何使用环境变量覆盖 ASP.NET Core 配置数组设置
ASP.NET Core运行两个TestServer进行集成测试
覆盖 asp.net core razor 页面中的 razor 视图