使用多个标识用户时,没有针对 Identity.UserManager 类型的服务



我的设置

目前,我有两个继承自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包含共享属性,如名字和姓氏。StudentUserEmployeeUser都有自己的属性和关系。此结构遵循每个层次结构的表 (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

手动将StudentUserEmployeeUser添加为作用域服务似乎不起作用(作为第一个答案提到(。

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才能正确设置IndentityBuilderRole属性,然后由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>();

相关内容

最新更新