如何覆盖 ASP.NET Core Identity 的密码策略
How override ASP.NET Core Identity's password policy
默认情况下,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()
};
}
}
}
我在启动的 class 中添加了此用户管理器依赖项:
services.AddScoped<ApplicationUserManager>();
但是当我在控制器中使用 ApplicationUserManager 时,出现错误:
处理请求时出现未处理的异常。
InvalidOperationException:尝试激活 'ApplicationUserManager'.
时无法解析类型 'Microsoft.EntityFrameworkCore.DbContextOptions`1[SecurityDbContext]' 的服务
编辑: 当我使用 ASP.NET Core Identity 的默认 classes 时,用户管理有效,所以这不是数据库问题,或者类似的问题
编辑 2:我找到了解决方案,您只需在启动的 class 中配置 Identity。我的回答给出了一些细节。
最后很简单...
无需覆盖任何 class,您只需在启动时配置身份设置 class,如下所示:
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绝对是个好东西...
您可以在 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,
};
}
附加要求:
If you feel this password constraint is not enough, You can define your
own conditions by inheriting the
PasswordValidator class.
示例实现:
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());
}
}
我已经在我的 class 中覆盖了 ValidateAsync 方法,并且在这个方法中我正在实施我的自定义密码策略。
非常非常重要
- ValidateAsync() 中的第一行代码
IdentityResult result = await base.ValidateAsync(manager, user, password);
:
根据 Statup 的 ConfigureServices 方法中给出的密码规则验证密码 class(旧答案中显示的那个 post)
- 密码验证功能由
Microsoft.AspNetCore.Identity 命名空间中的 IPasswordValidator 接口。所以我需要将我的“CustomPasswordPolicy”class注册为“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();
Offical Github Documentation of PasswordValidator.cs (for better
understanding): here
开发人员最简单的方法是
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.
将以下行添加到 startup.cs
的 ConfigureServices 方法中
services.Configure<IdentityOptions>(Configuration.GetSection(nameof(IdentityOptions)));
如果需要,您可以使用不同的部分名称
然后将设置添加到配置。您可以在多个配置源中添加多个设置,它们将被合并。
例如。我把它放在我的 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 的密码策略要求至少一个特殊字符,一个大写字母,一个数字,...
如何更改此限制?
文档中没有相关内容 (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()
};
}
}
}
我在启动的 class 中添加了此用户管理器依赖项:
services.AddScoped<ApplicationUserManager>();
但是当我在控制器中使用 ApplicationUserManager 时,出现错误: 处理请求时出现未处理的异常。
InvalidOperationException:尝试激活 'ApplicationUserManager'.
时无法解析类型 'Microsoft.EntityFrameworkCore.DbContextOptions`1[SecurityDbContext]' 的服务编辑: 当我使用 ASP.NET Core Identity 的默认 classes 时,用户管理有效,所以这不是数据库问题,或者类似的问题
编辑 2:我找到了解决方案,您只需在启动的 class 中配置 Identity。我的回答给出了一些细节。
最后很简单...
无需覆盖任何 class,您只需在启动时配置身份设置 class,如下所示:
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绝对是个好东西...
您可以在 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,
};
}
附加要求:
If you feel this password constraint is not enough, You can define your own conditions by inheriting the PasswordValidator class.
示例实现:
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());
}
}
我已经在我的 class 中覆盖了 ValidateAsync 方法,并且在这个方法中我正在实施我的自定义密码策略。
非常非常重要
- ValidateAsync() 中的第一行代码
IdentityResult result = await base.ValidateAsync(manager, user, password);
:
根据 Statup 的 ConfigureServices 方法中给出的密码规则验证密码 class(旧答案中显示的那个 post)
- 密码验证功能由 Microsoft.AspNetCore.Identity 命名空间中的 IPasswordValidator 接口。所以我需要将我的“CustomPasswordPolicy”class注册为“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();
Offical Github Documentation of PasswordValidator.cs (for better understanding): here
开发人员最简单的方法是
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.
将以下行添加到 startup.cs
的 ConfigureServices 方法中services.Configure<IdentityOptions>(Configuration.GetSection(nameof(IdentityOptions)));
如果需要,您可以使用不同的部分名称
然后将设置添加到配置。您可以在多个配置源中添加多个设置,它们将被合并。 例如。我把它放在我的 appsettings.local.json 文件中。 VCS 会忽略此文件,因此我的本地设置永远不会生效,这与您硬编码设置并使用 #if debug 或类似的东西不同。
"IdentityOptions": {
"Password": {
"RequiredLength": 6,
"RequireDigit": false,
"RequiredUniqueChars": 1,
"RequireLowercase": false,
"RequireNonAlphanumeric": false,
"RequireUppercase": false
}
}
这同样适用于 appsettings.{Environment}.json 或任何其他配置源,因此您可以在开发服务器和实时服务器上进行不同的设置,而无需更改代码或使用不同的构建配置