自定义 UserManager 总是返回 null [英] Custom UserManager always return null

查看:30
本文介绍了自定义 UserManager 总是返回 null的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建我自己的 UserManager 从原始扩展而来,当我通过电子邮件进行搜索时,没有找到用户.但是如果我从上下文中进行搜索,如果我找到了用户(参见 Get 方法).为了验证它是否真的很好地实现,我覆盖了 FindByEmailAsync 方法并且它确实被调用了,但我不知道为什么用户找不到它.一些帮助?谢谢!

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. But if I do a search from the context, if I find the user (see the Get method). 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. 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;

    }

}

推荐答案

注意:此答案引用了您的 Github 重现中显示的代码和值.

当您调用 UserManager.FindByEmailAsync 时,您传递给该方法的值是规范化的 - 默认情况下,此规范化会将值转换为大写.然后使用此标准化值来搜索 AspNetUsers 表中的 NormalizedEmail 列.

When you call UserManager.FindByEmailAsync, the value you pass into the method is normalised - by default, this normalisation converts the value to uppercase. This normalised value is then used to search the NormalizedEmail column in the AspNetUsers table.

在您的 MyIndentityContext.OnModelCreating 方法中,您有以下代码:

Inside of your MyIndentityContext.OnModelCreating method, you have the following code:

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

当您控制此处的数据并仅设置 Email 时,未设置数据库中的 NormalizedEmail 值(它是 null代码>).这意味着当您使用 UserManager.FindByEmailAsync 并在 NormalizedEmail 列中查找 A_MAIL@HOTMAIL.COM 时,没有匹配项.但是,当您直接使用DbSet 并查看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). This means that when you use UserManager.FindByEmailAsync and are looking for A_MAIL@HOTMAIL.COM in the NormalizedEmail column, there's no match. However, when you use the DbSet directly and look at the Email column, you can find a matching record for a_mail@hotmail.com.

为了解决这个问题,我建议您不要使用 HasData 来为您的用户做种,而是在您的种子方法中使用 UserManager.CreateAsync 方法.应用.这将确保规范化和其他相关处理在记录被持久化到数据库之前发生.

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. This will ensure that normalisation and other related processing occurrs as it should before the records are persisted in the database.

这篇关于自定义 UserManager 总是返回 null的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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