简体   繁体   English

自定义UserManager始终返回null

[英]Custom UserManager always return null

I am trying to create my own UserManager extending from the original, and when I do a search by email, the user is not found. 我试图创建自己的UserManager从原始用户扩展),当我通过电子邮件进行搜索时,找不到用户。 But if I do a search from the context, if I find the user (see the Get method). 但是,如果我从上下文进行搜索,是否找到了用户(请参阅Get方法)。 To verify that it is really well implemented, I overwrote the FindByEmailAsync method and it is really being called, but I do not know why the user can not find it. 为了验证它是否确实实现良好,我FindByEmailAsyncFindByEmailAsync方法,并确实对其进行了调用,但是我不知道为什么用户找不到它。 Some help? 一些帮助? Thank you! 谢谢!

public void ConfigureServices(IServiceCollection servicesCollection)
{
    servicesCollection.AddDbContext<MyIndentityContext>(currentOptions =>
        currentOptions.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    servicesCollection.AddIdentity<ApplicationUser, ApplicationRole>()
        .AddEntityFrameworkStores<MyIndentityContext>()
        .AddRoleStore<ApplicationRoleStore>()
        .AddUserStore<ApplicationUserStore>()
        .AddUserManager<ApplicationUserManager>()
        .AddRoleManager<ApplicationRoleManager>()
        .AddSignInManager<ApplicationSignInManager>()
        .AddDefaultTokenProviders();

        ...

        ...

        ...
}

public class MyIndentityContext : IdentityDbContext<ApplicationUser, ApplicationRole, string>
{
    private readonly IConfiguration _configuration;

    private readonly IHttpContextAccessor _httpContextAccessor;

    public MyIndentityContext(DbContextOptions dbContextOptions, IHttpContextAccessor httpContextAccessor,
        IConfiguration configuration)
        : base(dbContextOptions)
    {
        _configuration = configuration;
        _httpContextAccessor = httpContextAccessor;
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.HasDefaultSchema("Sample.API");
    }

}

public class ApplicationRoleManager : RoleManager<ApplicationRole>
{
    public ApplicationRoleManager(IRoleStore<ApplicationRole> roleStore,
        IEnumerable<IRoleValidator<ApplicationRole>> roleValidators, ILookupNormalizer keyNormalizer,
        IdentityErrorDescriber errors, ILogger<ApplicationRoleManager> logger) : base(roleStore,
        roleValidators,
        keyNormalizer, errors, logger)
    {
    }
}

public class ApplicationSignInManager : SignInManager<ApplicationUser>
{
    public ApplicationSignInManager(UserManager<ApplicationUser> userManager, IHttpContextAccessor contextAccessor,
        IUserClaimsPrincipalFactory<ApplicationUser> claimsFactory, IOptions<IdentityOptions> optionsAccessor,
        ILogger<ApplicationSignInManager> logger, IAuthenticationSchemeProvider schemes) : base(userManager,
        contextAccessor, claimsFactory, optionsAccessor, logger, schemes)
    {
    }
}

public class ApplicationUserManager : UserManager<ApplicationUser>
{
    public ApplicationUserManager(IUserStore<ApplicationUser> userStore, IOptions<IdentityOptions> optionsAccessor,
        IPasswordHasher<ApplicationUser> passwordHasher,
        IEnumerable<IUserValidator<ApplicationUser>> userValidators,
        IEnumerable<IPasswordValidator<ApplicationUser>> passwordValidators, ILookupNormalizer keyNormalizer,
        IdentityErrorDescriber errors, IServiceProvider services, ILogger<ApplicationUserManager> logger) :
        base(userStore, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors,
            services, logger)
    { }

    // Custom implementation to check if you are really calling the method
    public override Task<ApplicationUser> FindByEmailAsync(string email)
    {
        return Task.Run(() => new ApplicationUser
        {
            UserName = "A_NAME"
        });
    }
}

public class ApplicationRoleStore : RoleStore<ApplicationRole, MyIndentityContext>
{
    public ApplicationRoleStore(MyIndentityContext dbContext, IdentityErrorDescriber identityErrorDescriber)
        : base(dbContext, identityErrorDescriber)
    {}
}

public class ApplicationUserStore : UserStore<ApplicationUser, ApplicationRole, MyIndentityContext, string>
{
    public ApplicationUserStore(MyIndentityContext dbContext, IdentityErrorDescriber identityErrorDescriber)
        : base(dbContext, identityErrorDescriber)
    {}

}

public class ApplicationUser : IdentityUser {}

public class ApplicationRole : IdentityRole
{
    public ApplicationRole() { }

    public ApplicationRole(string roleName) : base(roleName) { }

    public ApplicationRole(string roleName, string roleDescription) : base(roleName)
    {
        Description = roleDescription;
    }

}

[Authorize]
[ApiController]
[Route("api/[controller]")]
[EnableCors(CORS.AllowSpecificOrigins)]

public class UserController : BaseController
{
    private readonly ApplicationUserManager _applicationUserManager;

    public UserController(ApplicationUserManager applicationUserManager)
    {
        _applicationUserManager = applicationUserManager;
    }

     // GET: api/User/5
    [HttpGet("{id}")]
    public async Task<UserDTO> Get(int id)
    {

            var currentUser = await _applicationUserManager.FindByEmailAsync("example@example.com"); ==> RETURN NULL!

            var otherUser = _indentityContext.Users.Where(x => x.Email == "example@example.com"); ==> RETURN CORRECT USER!

            return currentUser;

    }

}

Note: This answer references code and values shown in your Github repro. 注意:此答案引用了Github复制程序中显​​示的代码和值。

When you call UserManager.FindByEmailAsync , the value you pass into the method is normalised - by default, this normalisation converts the value to uppercase. 调用UserManager.FindByEmailAsync ,传递给该方法的值将被规范化-默认情况下,此规范化将值转换为大写。 This normalised value is then used to search the NormalizedEmail column in the AspNetUsers table. 然后,该标准化值用于搜索AspNetUsers表中的NormalizedEmail列。

Inside of your MyIndentityContext.OnModelCreating method, you have the following code: MyIndentityContext.OnModelCreating方法的内部,您具有以下代码:

modelBuilder.Entity<ApplicationUser>().HasData(
    new ApplicationUser
    {
        Email = "a_mail@hotmail.com"
    });

As you're taking control of the data here and setting only Email , the NormalizedEmail value in the database is not being set (it's null ). 当您在此处控制数据并仅设置Email ,未在数据库中设置NormalizedEmail值(它为null )。 This means that when you use UserManager.FindByEmailAsync and are looking for A_MAIL@HOTMAIL.COM in the NormalizedEmail column, there's no match. 这意味着当您使用UserManager.FindByEmailAsync并在NormalizedEmail列中查找A_MAIL@HOTMAIL.COM时,没有匹配项。 However, when you use the DbSet directly and look at the Email column, you can find a matching record for a_mail@hotmail.com . 但是,当您直接使用DbSet并查看“ Email列时, 可以找到a_mail@hotmail.com的匹配记录。

To resolve this, I recommend that instead of using HasData to seed your user(s), you use the UserManager.CreateAsync method inside of a seed method within your application. 要解决此问题,我建议您不要在应用程序中的种子方法内使用UserManager.CreateAsync方法,而不要使用HasData为用户种子。 This will ensure that normalisation and other related processing occurrs as it should before the records are persisted in the database. 这将确保在将记录保留在数据库中之前进行规范化和其他相关处理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM