为 .NET Core Identity 2.1 覆盖 UserValidator.cs 中的 ValidateAsync [英] Override ValidateAsync in UserValidator.cs for .NET Core Identity 2.1

查看:12
本文介绍了为 .NET Core Identity 2.1 覆盖 UserValidator.cs 中的 ValidateAsync的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在自定义用户名验证以允许相同的用户名(非唯一).这是一个附加字段已删除",作为对身份用户的软删除.因此自定义涉及更改当前验证以检查用户名是否已存在并且已删除为 false 以仅触发 DuplicateUserName 错误.

I'm customizing the validation for username to allow the same username (non-unique). This is with an additional field "Deleted" as a soft delete to identity user. So the customization involves changing the current validation to check if the username already exist and deleted is false to only trigger DuplicateUserName error.

我所做的是创建一个 CustomUserValidator 类,并覆盖 UserValidator.cs 中的 ValidateAsync 方法以及 ValidateUserName 方法.下面是代码:

What I've done is create a CustomUserValidator class, and override the ValidateAsync method in UserValidator.cs as well as the ValidateUserName method. Below is the code:

CustomUserValidator.cs

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 中

And in Startup.cs

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

CustomUserValidator 中的 ValidateAsync 方法中的代码工作正常,但似乎原始 ValidateAsync 也在运行.我之所以这么说是因为:

The code in ValidateAsync method in CustomUserValidator works fine, but it seems the original ValidateAsync is running as well. Why I say so is because:

  1. 在调试时,DuplicateUserName() 没有被调用,但仍然收到重复用户名错误.
  2. 通过放置特殊字符测试其他用户名验证.验证失败,特殊字符不允许出现两次错误!

我在这里做错了什么或错过了什么?提前致谢.

What am I doing wrong or missing here? Thanks in advance.

推荐答案

先说明问题

原因是身份库注入了使用默认库的验证用户类,即UserValidator.

The reason is why the Identity library injects the validate user class that uses the default library, which is UserValidator.

解决方案只是注入一个 CustomUserValidator.发生的情况是,如果将它注入到正常的实现中,它所做的就是添加 2 个 UserValidator,第一个是身份库的默认值,第二个是您实现 CustomUserIdentity 的那个.

The solution is only to inject a CustomUserValidator. What happens is that if it is injected into the normal implementation, what it does is that it adds 2 UserValidator, the first is the default by the identity library and the second would be the one that you implemented the CustomUserIdentity.

然后要仅注入 CustomUserIdentity,您必须创建一个新的 CustomUserManager 才能注入新的 ICustomUserValidator,这样它就不会采用默认的 IUserValidator.

Then to inject only the CustomUserIdentity you must create a new CustomUserManager to be able to inject the new ICustomUserValidator so that it does not take the one that is by default IUserValidator.

这是我的解决方案:

这是接口 ICustomUserValidator

This is the interface 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

And this one for the 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)
    {
    }
}

请注意,我使用 ICustomUserValidator

在 Startup 类中你必须注入新类:

In the Startup class you have to inject the new class:

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

最后注入这个类

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

我希望这个实现对你有所帮助.

I hope this implementation helps you.

这篇关于为 .NET Core Identity 2.1 覆盖 UserValidator.cs 中的 ValidateAsync的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆