Пользователь создается до того, как пользовательский валидатор запускается в Identity core - PullRequest
0 голосов
/ 02 августа 2020

Я использую ядро ​​идентификации для управления пользователями в. net core 3.1 web api. Теперь я хочу проверить электронную почту пользователей на предмет чего-либо, и только если это соответствует требованиям, он будет создан. Приведенный ниже код многое говорит о том, чего я хочу достичь

У меня есть пользовательский валидатор, как показано ниже:

 public class CustomEmailValidator<TUser> : IUserValidator<TUser>
   where TUser : User
{

    public Task<IdentityResult> ValidateAsync(UserManager<TUser> manager,
                                              TUser user)
    {
        User userFromEmail = null;

        if(!string.IsNullOrEmpty(user.Email))
            userFromEmail = manager.FindByEmailAsync(user.Email).Result;

        if (userFromEmail == null)
            return Task.FromResult(IdentityResult.Success);

        return Task.FromResult(
        IdentityResult.Failed(new IdentityError
        {
            Code = "Err",
            Description = "You are already registered with us."
        }));
    }
}

Я добавляю валидатор в свой запуск, как показано ниже:

services.AddDbContext<DataContext>(x => x.UseSqlite(Configuration.GetConnectionString("DefaultConnection")));

        IdentityBuilder builder = services.AddIdentityCore<User>(opt =>
        {
            
            opt.User.RequireUniqueEmail = false;
            opt.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyz0123456789._-";
            opt.Password.RequireDigit = true;
            opt.Password.RequiredLength = 6;
            opt.Password.RequireNonAlphanumeric = true;
            opt.Password.RequireUppercase = true;
            opt.Password.RequireLowercase = true;
        })
        .AddUserValidator<CustomEmailValidator<User>>();
        builder = new IdentityBuilder(builder.UserType, typeof(Role), builder.Services);
        builder.AddEntityFrameworkStores<DataContext>();
        builder.AddRoleValidator<RoleValidator<Role>>();
        builder.AddRoleManager<RoleManager<Role>>();
        builder.AddSignInManager<SignInManager<User>>();

Как видно, я хочу использовать проверку пользователя по умолчанию и свою настраиваемую проверку. Проблема в том, что пользователь создается сразу после проверки по умолчанию, и электронная почта всегда оказывается такой, как существует в моей настраиваемой проверке. Я действительно не хочу отменять мои проверки по умолчанию.

Создание пользователя, как показано ниже:

    [HttpPost("Register")]
    public async Task<IActionResult> Register(UserForRegisterDto userForRegister)
    {
        var userToCreate = _mapper.Map<User>(userForRegister);

        var result = await _userManager.CreateAsync(userToCreate, userForRegister.Password);

        if (result.Succeeded)
        {
            var roleresult = await _userManager.AddToRoleAsync(userToCreate, "Member");
            return Ok(roleresult);
        }
        return BadRequest(result.Errors);
    }

Примечание Это не мой фактический вариант использования. Я знаю, что могу проверить уникальный адрес электронной почты при проверке по умолчанию, установив opt.User.RequireUniqueEmail = true. Это просто проясняет концепцию для дальнейшей разработки.

Обновление После дальнейшей отладки я вижу, что специальный метод проверки вызывается дважды. Один раз перед созданием пользователя и один раз после создания по какой-то причине. Я вставляю новый уникальный адрес электронной почты, и настраиваемая проверка проходит успешно, и после создания пользователя настраиваемая проверка вызывается снова, обнаруживает уже зарегистрированный адрес электронной почты и выдает сообщение об ошибке. Это странно

1 Ответ

0 голосов
/ 21 августа 2020

Обнаружено, что AddToRoleAsyn c снова вызывает настраиваемый валидатор и находит пользователя, присутствующего в таблице. Пришлось включить проверку, совпадает ли пользователь, найденный в таблице с тем же адресом электронной почты, с пользователем, получающим обновления.

Код ниже:

 public class CustomEmailValidator<TUser> : IUserValidator<TUser>
 where TUser : User
{

  public Task<IdentityResult> ValidateAsync(UserManager<TUser> manager,
                                          TUser user)
  {
    User userFromEmail = null;

    if(!string.IsNullOrEmpty(user.Email))
        userFromEmail = manager.FindByEmailAsync(user.Email).Result;

    if (userFromEmail == null)
        return Task.FromResult(IdentityResult.Success);
    else {
            if(string.Equals(userFromEmail.Id, user.Id))
            {
                return Task.FromResult(IdentityResult.Success);
            }
    }

    return Task.FromResult(
    IdentityResult.Failed(new IdentityError
    {
        Code = "Err",
        Description = "You are already registered with us."
    }));
  }
}

Это должно помочь многим людям

...