自定义 UserManager 总是返回 null [英] Custom UserManager always return 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屋!