【问题标题】:Custom UserManager always return null自定义 UserManager 总是返回 null
【发布时间】:2018-07-25 13:40:43
【问题描述】:

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

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;

    }

}

【问题讨论】:

  • 如果您还没有看过Custom storage providers for ASP.NET Core Identity,那可能会给您一些建议。
  • return Task.Run(...) 永远不会工作。我认为这只是示例代码,但请尝试return Task.FromResult(new ApplicationUser { UserName = "A_NAME" }); 让它工作。
  • 你能和我们分享一个项目吗?我用你当前的代码做了一个测试,它工作正常。您是否使用多个DbContext?您是否通过Task.Run(() =&gt; new ApplicationUser { UserName = "A_NAME" }); 获得用户?
  • @Edward 嗨!我只使用一个上下文。我添加了 Task.Run 以验证 FindByEmailAsync 方法是否实际被调用。这将返回一个名为“A_NAME”的用户。后来我留下了一个带有代码的github链接。
  • @Edward 检查存储库。 github.com/avechuche/Sample.API.git

标签: c# asp.net-core asp.net-core-2.1 asp.net-core-identity


【解决方案1】:

注意:此答案引用了您的 Github 复制中显示的代码和值。

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

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

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 的匹配记录。

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

【讨论】:

    猜你喜欢
    • 2019-07-21
    • 2019-04-09
    • 2014-03-04
    • 2016-11-02
    • 2014-05-06
    • 2012-06-05
    • 2014-05-30
    • 2014-02-23
    • 2017-10-12
    相关资源
    最近更新 更多