Validation 重写.NET Core Identity 2.1的UserValidator.cs中的ValidateAsync

Validation 重写.NET Core Identity 2.1的UserValidator.cs中的ValidateAsync,validation,asp.net-core-mvc,asp.net-identity,Validation,Asp.net Core Mvc,Asp.net Identity,我正在自定义用户名验证,以允许使用相同的用户名(非唯一)。这是一个附加字段“已删除”,作为对身份用户的软删除。因此,定制涉及更改当前验证以检查用户名是否已存在,并且删除的用户名是否为false以仅触发DuplicateUserName错误 我所做的是创建一个CustomUserValidator类,并重写UserValidator.cs中的ValidateAsync方法以及ValidateUserName方法。代码如下: CustomUserValidator.cs public class C

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

我所做的是创建一个CustomUserValidator类,并重写UserValidator.cs中的ValidateAsync方法以及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));
            }
        }
    }
}
公共类CustomUserValidator:UserValidator
其中TUser:ApplicationUser
{
公共覆盖异步任务ValidateAsync(UserManager,TUser用户)
{
if(manager==null)
{
抛出新的ArgumentNullException(nameof(manager));
}
if(user==null)
{
抛出新ArgumentNullException(nameof(user));
}
var errors=新列表();
等待ValidateUserName(经理、用户、错误);
if(manager.Options.User.RequireUniqueEmail)
{
等待ValidateEmail(经理、用户、错误);
}
返回errors.Count>0?IdentityResult.Failed(errors.ToArray()):IdentityResult.Success;
}
专用异步任务ValidateUserName(UserManager管理器、TUser用户、ICollection错误)
{
var userName=await manager.GetUserNameAsync(用户);
if(string.IsNullOrWhiteSpace(用户名))
{
添加(descripber.InvalidUserName(用户名));
}
如果(!string.IsNullOrEmpty(manager.Options.User.AllowedUserNameCharacters),则为else&&
userName.Any(c=>!manager.Options.User.AllowedUserNameCharacters.Contains(c)))
{
添加(descripber.InvalidUserName(用户名));
}
其他的
{
//var owner=await manager.FindByNameAsync(用户名);
var owner=manager.Users.Where(x=>!x.Deleted&&
x、 UserName.ToUpper()==UserName.ToUpper())
.FirstOrDefault();
如果(所有者)=null&&
!string.Equals(wait manager.GetUserIdAsync(所有者),wait manager.GetUserIdAsync(用户)))
{
添加(descripber.DuplicateUserName(用户名));
}
}
}
}
在Startup.cs中

public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<IUserValidator<ApplicationUser>, CustomUserValidator<ApplicationUser>>();
}
public void配置服务(IServiceCollection服务)
{
services.AddTransient();
}
CustomUserValidator中ValidateAsync方法中的代码工作正常,但原始ValidateAsync似乎也在运行。我之所以这样说,是因为:

  • 调试时,不会调用DuplicateUserName(),但仍会收到DuplicateUserName错误
  • 通过放置特殊字符测试其他用户名验证。验证失败,不允许使用特殊字符错误两次 我做错了什么或错过了什么?
    提前谢谢。

    首先让我解释一下这个问题

    原因是标识库注入了使用默认库(UserValidator)的validate user类

    解决方案只是注入CustomUserValidator。如果它被注入到正常的实现中,它会添加2个UserValidator,第一个是identity库的默认值,第二个是实现CustomUserIdentity的值

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

    这是我的解决方案:

    这是接口ICustomUserValidator

        public interface ICustomUserValidator<TUser> : IUserValidator<TUser> where TUser : ApplicationUser
    {
    }
    
    公共接口ICustomUserValidator:IUserValidator其中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
        }
    }
    
    公共类CustomUserValidator:UserValidator,ICustomUserValidator
    其中TUser:ApplicationUser
    {
    公共异步任务ValidateAsync(UserManager,TUser用户)
    {
    //一些代码
    }
    专用异步任务ValidateUserName(UserManager管理器、TUser用户、ICollection错误)
    {
    //一些代码
    }
    }
    
    这张是给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)
        {
        }
    }
    
    公共类CustomUserManager:UserManager 其中TUser:ApplicationUser { public CustomUserManager(IUserStore存储、IOOptions访问器、, IPasswordHasher密码hasher,IEnumerable用户验证程序, IEnumerable PasswordValidator、ILookupNormalizer、keyNormalizer、, IdentityErrorDescriber错误,IServiceProvider令牌提供程序, ILogger(记录器) :基本( store、OptionAccessor、passwordHasher、userValidators、passwordValidators、keyNormalizer、errors、, 令牌提供者(日志记录器) { } } 请注意,我放置了ICustomUserValidator,而不是IUserValidator

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

            services.AddIdentity<ApplicationUser, IdentityRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddUserManager<CustomUserManager<ApplicationUser>>()
    
    services.AddIdentity()
    .AddEntityFrameworkStores()
    .AddUserManager()
    
    最后注入这个类

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

    我希望此实现对您有所帮助。

    在注册身份之前替换默认的UserValidator

    services.AddTransient<IUserValidator<ApplicationUser>, CustomUserValidator<ApplicationUser>>();  // before Identity
    services.AddDefaultIdentity<ApplicationUser>().AddRoles<Role>()
    .AddEntityFrameworkStores<IdentityDbContext>()
    .AddDefaultTokenProviders();
    
    services.AddTransient();//身份之前
    services.AddDefaultIdentity().AddRoles()
    .AddEntityFrameworkStores()
    .AddDefaultTokenProviders();
    
    核心3.1中的语法略有不同:

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

    services.addtransient在我的例子中,您提到的代码不会被触发。因为我是用一个软删除的用户名创建的,这个用户名也能正常工作。所以,不管是否注释代码,对我来说都不会有什么不同。但是,正如我在第1项中提到的,DuplicateUserName()仍然会被触发,尽管在我调试时不是这样