我的设置
目前,我有两个继承自ApplicationUser
的模型,它们继承了IdentityUser
。用户类包括:
public abstract class ApplicationUser : IdentityUser
{
[PersonalData]
public string FirstName { get; set; }
[PersonalData]
public string LastName { get; set; }
[NotMapped]
public string FullName => $"{FirstName} {LastName}";
}
public class StudentUser : ApplicationUser
{
[PersonalData]
[Required]
public string StudentNumber { get; set; }
// A user belongs to one group
public Group Group { get; set; }
}
public class EmployeeUser : ApplicationUser { }
ApplicationUser
包含共享属性,如名字和姓氏。StudentUser
和EmployeeUser
都有自己的属性和关系。此结构遵循每个层次结构的表 (TPH( 继承。
理想情况下,我想遵循每个类型表 (TPT( 继承,因为 SQL 结构更好。 ASP.NET Core 本身只支持 TPH,所以这就是我遵循 TPT 方法的原因。
问题所在
我在Startup.cs
中添加了身份服务:
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
当我调用UserManager<StudentUser>
或UserManager<EmployeeUser>
时,出现以下错误:
尚未注册类型"Microsoft.AspNetCore.Identity.UserManager'1[ClassroomMonitor.Models.StudentUser]"的服务。
我的问题
不幸的是,我找不到太多关于此错误与此实现相结合的信息。
(甚至(有可能让它以这种方式工作吗?
欢迎任何帮助或想法。
更新 1
手动将StudentUser
或EmployeeUser
添加为作用域服务似乎不起作用(作为第一个答案提到(。
services.AddScoped<UserManager<ApplicationUser>, UserManager<ApplicationUser>>();
// or..
services.AddScoped<UserManager<ApplicationUser>>();
这将引发以下错误:
InvalidOperationException: 无法解析类型'Microsoft.AspNetCore.Identity.IUserStore1[ClassroomMonitor.Models.StudentUser]"的服务
更新 2
这里有一个要点,可以让您更好地了解项目结构:
理想情况下,应为派生用户类型调用与基本用户类型相同的标识设置。
不幸的是AddIdentity
该方法包含一些代码,可以防止多次使用它。
相反,您可以使用AddIdentityCore
.角色服务已经由AddIdentity
注册,唯一的区别是AddIdentityCore
注册UserClaimsPrincipalFactory<TUser>
,所以为了匹配AddIdentity
设置,需要通过AddClaimsPrincipalFactory
方法将其替换为UserClaimsPrincipalFactory<TUser, TRole>
。
代码如下所示:
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders()
.AddDefaultUI();
services.AddIdentityCore<StudentUser>()
.AddRoles<IdentityRole>()
.AddClaimsPrincipalFactory<UserClaimsPrincipalFactory<StudentUser, IdentityRole>>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders()
.AddDefaultUI();
services.AddIdentityCore<EmployeeUser>()
.AddRoles<IdentityRole>()
.AddClaimsPrincipalFactory<UserClaimsPrincipalFactory<EmployeeUser, IdentityRole>>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders()
.AddDefaultUI();
当然,您可以在自定义扩展方法中移动公共部分。
更新:尽管已经配置了角色服务,但您仍然需要调用AddRoles
才能正确设置IndentityBuilder
的Role
属性,然后由AddEntityFrameworkStores
使用。
在新项目上测试:
dotnet 新 mvc --身份验证个人
Startup.cshtml
services.AddDefaultIdentity<User>()
.AddEntityFrameworkStores<ApplicationDbContext>();
用户.cs
public class User : IdentityUser
{
public string Test { get; set; }
}
可能这是你的问题:
_LoginPartial.cshtml
@inject SignInManager<User> SignInManager
@inject UserManager<User> UserManager
还以这种方式进行了测试:
启动.cs
services.AddDefaultIdentity<User2>()
.AddEntityFrameworkStores<ApplicationDbContext>();
用户.cs
public class User : IdentityUser
{
public string TestA { get; set; }
}
public class User2 : User
{
public string TestB { get; set; }
}
_LoginPartial.cshtml
@inject SignInManager<User2> SignInManager
@inject UserManager<User2> UserManager
您缺少它的寄存器 DI。
services.AddScoped<UserManager<AppUser>, UserManager<AppUser>>()
StudentUser 和 EmployeeUser 与此类似
您不能为不同的用户类型添加作用域,您实际上不应该有许多从 IdentityUser 派生的不同类型,因为这意味着您将在各个地方使用不正确的类型或在数据库中使用多个不同的用户表。
您应该真正构建数据,使其具有由员工实体(单独的实体(或学生实体(再次是单独的实体(引用的ApplicationUser
。 这里更多的是设计问题,而不是代码问题。
ASPIdentity 将在您AddIdentity<ApplicationUser, IdentityRole>
时注入Usermanager<ApplicationUser>
,因此添加更多用户管理器将无法按预期工作。
答案您必须为每种类型的用户创建不同的实体,1 用于学生,1 用于员工等,这些实体都将具有用户 ID 的外键,这将使您能够添加多种类型的用户,而无需为每个用户类型使用不同的表。
然后,当您addIdentity
时,您可以注册ApplicationUser
(就像目前一样(,然后注入UserManager<ApplicationUser>
这将获得用户类型。
如果核心>=3.0
services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<WorldContext>();