Переопределить ValidateAsync в UserValidator.cs для .NET Core Identity 2.1 - PullRequest
0 голосов
/ 10 июня 2018

Я настраиваю проверку для имени пользователя, чтобы разрешить одно и то же имя пользователя (не уникальное).Это с дополнительным полем «Удалено» как мягкое удаление для идентификации пользователя.Таким образом, настройка включает в себя изменение текущей проверки, чтобы проверить, существует ли уже имя пользователя, и удалено ли значение false, чтобы вызвать только ошибку DuplicateUserName.

Что я сделал, так это создал класс CustomUserValidator и переопределил метод ValidateAsync в UserValidator.cs, а также метод ValidateUserName.Ниже приведен код:

CustomUserValidator.cs

public class CustomUserValidator<TUser> : UserValidator<TUser>
    where TUser : ApplicationUser
{
    public override async Task<IdentityResult> ValidateAsync(UserManager<TUser> manager, TUser user)
    {
        if (manager == null)
        {
            throw new ArgumentNullException(nameof(manager));
        }
        if (user == null)
        {
            throw new ArgumentNullException(nameof(user));
        }
        var errors = new List<IdentityError>();
        await ValidateUserName(manager, user, errors);
        if (manager.Options.User.RequireUniqueEmail)
        {
            await ValidateEmail(manager, user, errors);
        }
        return errors.Count > 0 ? IdentityResult.Failed(errors.ToArray()) : IdentityResult.Success;
    }

    private async Task ValidateUserName(UserManager<TUser> manager, TUser user, ICollection<IdentityError> errors)
    {
        var userName = await manager.GetUserNameAsync(user);
        if (string.IsNullOrWhiteSpace(userName))
        {
            errors.Add(Describer.InvalidUserName(userName));
        }
        else if (!string.IsNullOrEmpty(manager.Options.User.AllowedUserNameCharacters) &&
            userName.Any(c => !manager.Options.User.AllowedUserNameCharacters.Contains(c)))
        {
            errors.Add(Describer.InvalidUserName(userName));
        }
        else
        {
            //var owner = await manager.FindByNameAsync(userName);
            var owner = manager.Users.Where(x => !x.Deleted &&
                x.UserName.ToUpper() == userName.ToUpper())
                .FirstOrDefault();
            if (owner != null &&
                !string.Equals(await manager.GetUserIdAsync(owner), await manager.GetUserIdAsync(user)))
            {
                errors.Add(Describer.DuplicateUserName(userName));
            }
        }
    }
}

И в Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<IUserValidator<ApplicationUser>, CustomUserValidator<ApplicationUser>>();
}

Код в методе ValidateAsync в CustomUserValidator работает нормально, но, похоже,оригинальный ValidateAsync также работает.Я так говорю потому, что:

  1. Во время отладки DuplicateUserName () не вызывается, но все еще получает ошибку дублированного имени пользователя.
  2. Проверено на проверку другого имени пользователя с помощью специальных символов.Ошибка проверки со специальными символами не допускает ошибки дважды!

Что я делаю неправильно или отсутствует здесь?Заранее спасибо.

Ответы [ 2 ]

0 голосов
/ 06 марта 2019

Заменить UserValidator по умолчанию перед регистрацией личности

services.AddTransient<IUserValidator<ApplicationUser>, CustomUserValidator<ApplicationUser>>();  // before Identity
services.AddDefaultIdentity<ApplicationUser>().AddRoles<Role>()
.AddEntityFrameworkStores<IdentityDbContext>()
.AddDefaultTokenProviders();
0 голосов
/ 27 сентября 2018

Сначала позвольте мне объяснить проблему

Причина в том, что библиотека Identity внедряет валидированный пользовательский класс, который использует библиотеку по умолчанию, которая является UserValidator.

Решение состоит только в том, чтобы внедритьCustomUserValidator.Случается так, что, если он внедряется в обычную реализацию, он добавляет 2 UserValidator, первый из которых является библиотекой идентификаторов по умолчанию, а второй - тот, который вы реализовали CustomUserIdentity.

Затем, чтобы внедрить только CustomUserIdentity, вы должны создать новый CustomUserManager, чтобы иметь возможность внедрять новый ICustomUserValidator, чтобы он не использовал тот, который по умолчанию является IUserValidator.

Это мое решение:

Это интерфейс ICustomUserValidator

    public interface ICustomUserValidator<TUser> : IUserValidator<TUser> where TUser : ApplicationUser
{
}

И реализация класса

public class CustomUserValidator<TUser> : UserValidator<TUser>, ICustomUserValidator<TUser>
    where TUser : ApplicationUser
{

    public async Task<IdentityResult> ValidateAsync(UserManager<TUser> manager, TUser user)
    {
        //Some Code
    }

    private async Task ValidateUserName(UserManager<TUser> manager, TUser user, ICollection<IdentityError> errors)
    {
        //Some Code
    }
}

И этот для CustomUserManager

    public class CustomUserManager<TUser> : UserManager<TUser>
            where TUser : ApplicationUser
{
    public CustomUserManager(IUserStore<TUser> store, IOptions<IdentityOptions> optionsAccessor,
        IPasswordHasher<TUser> passwordHasher, IEnumerable<ICustomUserValidator<TUser>> userValidators,
        IEnumerable<IPasswordValidator<TUser>> passwordValidators, ILookupNormalizer keyNormalizer,
        IdentityErrorDescriber errors, IServiceProvider tokenProviders,
        ILogger<UserManager<TUser>> logger)
        : base(
            store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors,
            tokenProviders, logger)
    {
    }
}

Обратите внимание, что вместоIUserValidator, я поставил ICustomUserValidator

В классе запуска вы должны добавить новый класс:

        services.AddIdentity<ApplicationUser, IdentityRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddUserManager<CustomUserManager<ApplicationUser>>()

И, наконец, внедрить этот класс

            services.AddTransient<ICustomUserValidator<ApplicationUser>, CustomUserValidator<ApplicationUser>>();

Я надеюсь, что эта реализация поможет вам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...