Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core 7
Система ASP.NET Identity уже имеет ряд ограничений на вводимые данные, которые нам надо использовать. Например, если мы возьмем любой проект с ASP.NET Core Identity, например, созданный в прошлых темах, то мы заметим, что для валидации пароля в Identity уже заложен ряд ограничений:
При вводе пароля срабатывает встроенная логика, согласно которой длина пароля не может быть меньше 6 символов, пароль должен содержать как минимум один цифровой и один не алфавитно-цифровой символ, а также как минимум один алфавитный символ должен быть в верхнем регистре. Но что, если нам надо установить другую минимальную длину пароля? Или что если мы хотим, чтобы в пароле могли бы использоваться только цифровые или только алфавитные символы?
И несмотря на то, что встроенная логика валидации скрыта от наших глаз, мы ее можем переопределить с помощью объекта Microsoft.AspNetCore.Identity.PasswordOptions.
Чтобы его применить, необходимо изменить код добавления контекста в классе Startup в методе ConfigureServices()
, который по умолчанию имеет следующее содержимое:
services.AddIdentity<User, IdentityRole>() .AddEntityFrameworkStores<ApplicationContext>();
Итак, изменим данный код следующим образом:
services.AddIdentity<User, IdentityRole>(opts=> { opts.Password.RequiredLength = 5; // минимальная длина opts.Password.RequireNonAlphanumeric = false; // требуются ли не алфавитно-цифровые символы opts.Password.RequireLowercase = false; // требуются ли символы в нижнем регистре opts.Password.RequireUppercase = false; // требуются ли символы в верхнем регистре opts.Password.RequireDigit = false; // требуются ли цифры }) .AddEntityFrameworkStores<ApplicationDbContext>();
Класс PasswordOptions предоставляет следующие свойства:
RequiredLength
: минимальная длина пароля
RequireNonLetterOrDigit
: если равно true, то пароль должен будет иметь как минимум один символ, который не является алфавитно-цифровым
RequireDigit
: если равно true, то пароль должен будет иметь как минимум одну цифру
RequireLowercase
: если равно true, то пароль должен будет иметь как минимум один символ в нижнем регистре
RequireUppercase
: если равно true, то пароль должен будет иметь как минимум один символ в верхнем регистре
Если мы меняем длину пароля, то соответственно нам надо изменить определение модели регистрации, если она устанавливает ограничение на длину:
public class RegisterViewModel { [Required] [Display(Name = "Email")] public string Email { get; set; } [Required] [Display(Name = "Год рождения")] public int Year { get; set; } [Required] [DataType(DataType.Password)] [StringLength(100, ErrorMessage = "Поле {0} должно иметь минимум {2} и максимум {1} символов.", MinimumLength = 5)] [Display(Name = "Пароль")] public string Password { get; set; } [Required] [Compare("Password", ErrorMessage = "Пароли не совпадают")] [DataType(DataType.Password)] [Display(Name = "Подтвердить пароль")] public string PasswordConfirm { get; set; } }
Для большинства случаев настроек класса PasswordOptions вполне хватит, мы можем настроить минимальную длину пароля, ввод алфавитных, цифровых или не алфавитно-цифровых символов. Однако если нам потребуется более сложная логика валидации, то придется определять свой класс валидатора.
Объект валидатора представляет объект интерфейса IPasswordValidator<T>
:
public interface IPasswordValidator<T> where T : class { Task<IdentityResult> ValidateAsync(UserManager<T> manager, T user, string password); }
Метод ValidateAsync()
вызывается при валидации пароля. В качестве параметров он получает объект UserManager,
объект пользователя и сам пароль, который надо валидировать.
Результат метода представляет объект IdentityResult
, через статус которого можно узнать об успешности валидации: если
свойство Succeeded
равно true
, то валидация прошла успешно.
Итак, создадим новый класс, который назовем и который будет иметь следующий код:
using System; using System.Collections.Generic; using System.Text.RegularExpressions; using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; namespace CustomIdentityApp.Models { public class CustomPasswordValidator : IPasswordValidator<User> { public int RequiredLength { get; set; } // минимальная длина public CustomPasswordValidator(int length) { RequiredLength = length; } public Task<IdentityResult> ValidateAsync(UserManager<User> manager, User user, string password) { List<IdentityError> errors = new List<IdentityError>(); if (String.IsNullOrEmpty(password) || password.Length < RequiredLength) { errors.Add(new IdentityError { Description = $"Минимальная длина пароля равна {RequiredLength}" }); } string pattern = "^[0-9]+$"; if (!Regex.IsMatch(password, pattern)) { errors.Add(new IdentityError { Description = "Пароль должен состоять только из цифр" }); } return Task.FromResult(errors.Count == 0 ? IdentityResult.Success : IdentityResult.Failed(errors.ToArray())); } } }
Для проверки на длину в классе определено свойство RequiredLength. Кроме проверки количества символов пароль здесь также проверяется на соответствие регулярному выражению, которое говорит о том, что все символы должны представлять цифры (string pattern = "^[0-9]+$"). Таким образом, мы можем определить в методе различные способы проверок.
Если какая-то из проверок не будет пройдена, то в список ошибок добавляется очередная ошибка в виде объекта IdentityError. При отстутствии ошибок возвращается результат IdentityResult.Success
.
Для использования класса перейдем в класс Startup и изменим его метод ConfigureServices()
:
public void ConfigureServices(IServiceCollection services) { // Добавляем сервис валидатора пароля services.AddTransient<IPasswordValidator<User>, CustomPasswordValidator>(serv => new CustomPasswordValidator(6)); services.AddDbContext<ApplicationContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); services.AddIdentity<User, IdentityRole>() .AddEntityFrameworkStores<ApplicationContext>(); services.AddControllersWithViews(); }
Первый вызов добавляет зависимость для интерфейса IPasswordValidator в виде объекта CustomPasswordValidator.
И теперь, если мы введем некорректные с точки зрения нашего валидатора значения, то получим соответствующие сообщения: