[英]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. 为了验证它是否确实实现良好,我FindByEmailAsync
了FindByEmailAsync
方法,并确实对其进行了调用,但是我不知道为什么用户找不到它。 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.