使用多个身份用户时,Identity.UserManager类型不提供服务

时间:2018-10-08 07:41:35

标签: c# .net-core entity-framework-core roles

我的设置

当前,我有两个模型继承自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包含 shared 属性,例如名字和姓氏。 StudentUserEmployeeUser都有其自己的属性和关系。此结构遵循Table Per Hierarchy (TPH)继承。

理想情况下,我想遵循Table Per Type (TPT)继承,因为SQL结构会更好。 ASP.NET Core仅本地支持TPH,所以这就是为什么我采用这种方法。

问题

Startup.cs中,我添加了身份服务:

services.AddIdentity<ApplicationUser, IdentityRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();

当我致电UserManager<StudentUser>UserManager<EmployeeUser>时,出现以下错误:

  

没有注册类型为“ Microsoft.AspNetCore.Identity.UserManager`1 [ClassroomMonitor.Models.StudentUser]”的服务。

我的问题

不幸的是,我在此实现中找不到太多有关此错误的信息。是否有可能以这种方式工作?

欢迎任何帮助或想法。

更新1

手动添加StudentUserEmployeeUser作为范围服务似乎不起作用(称为第一个answer)。

services.AddScoped<UserManager<ApplicationUser>, UserManager<ApplicationUser>>();
// or..
services.AddScoped<UserManager<ApplicationUser>>();

这将引发以下错误:

  

InvalidOperationException:无法解析“ Microsoft.AspNetCore.Identity.IUserStore1 [ClassroomMonitor.Models.StudentUser]”类型的服务

更新2

这里是Gist,可以使您更好地了解项目结构:

5 个答案:

答案 0 :(得分:4)

理想情况下,您将为派生用户类型调用与基本用户类型相同的身份设置。

不幸的是,AddIdentity方法包含一些代码,这些代码无法多次使用。

您可以使用AddIdentityCore。角色服务已由AddIdentity注册,唯一的区别是AddIdentityCore注册了UserClaimsPrincipalFactory<TUser>,因此,为了匹配AddIdentity设置,需要将其替换为{{ 1}}通过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的{​​{1}}属性,然后由Role使用。

答案 1 :(得分:0)

您缺少它的寄存器DI。

services.AddScoped<UserManager<AppUser>, UserManager<AppUser>>()

StudentUser和EmployeeUser与之相似

答案 2 :(得分:0)

在新项目上进行了测试:

  

dotnet新的mvc --auth个人

Startup.cshtml

services.AddDefaultIdentity<User>()
    .AddEntityFrameworkStores<ApplicationDbContext>();

User.cs

public class User : IdentityUser
{
    public string Test { get; set; }
}

可能这是您的问题:

_LoginPartial.cshtml

@inject SignInManager<User> SignInManager
@inject UserManager<User> UserManager

也通过这种方式进行了测试:

Startup.cs

services.AddDefaultIdentity<User2>()
    .AddEntityFrameworkStores<ApplicationDbContext>();

Users.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

答案 3 :(得分:0)

您不能为不同的用户类型添加范围,实际上您应该没有从IdentityUser派生的许多不同类型,因为这将意味着您将在整个位置使用不正确的类型,或者将在数据库中使用多个不同的用户表。

您应该真正构造数据,使其具有一个typedef struct FragmentShaderArguments { array<texture2d<float>, 2> exampleTextures [[ id(0) ]]; } FragmentShaderArguments; fragment float4 fragmentShader( RasterizerData in [[ stage_in ]], device FragmentShaderArguments & fragmentShaderArgs [[ buffer(0) ]]) { constexpr sampler textureSampler (mag_filter::linear, min_filter::linear); float4 color = float4(0, 0, 0, 1); float4 color1 = fragmentShaderArgs.exampleTextures[0].sample(textureSampler, in.texCoord); float4 color2 = fragmentShaderArgs.exampleTextures[1].sample(textureSampler, in.texCoord); color = mix(color1, color2, 0.5); return color; } ,该值由员工实体(一个单独的实体)或Student实体(同样是一个单独的实体)引用。 这里更多的是设计问题,而不是代码问题。

当您ApplicationUser时,ASPIdentity将注入Usermanager<ApplicationUser>,因此添加更多的用户管理器将无法按预期进行。

答案  您必须为每种用户类型创建不同的实体,为学生创建1个实体,为员工创建1个实体,等等。这些实体都将具有用户ID的外键,这将使您能够添加多种类型的用户而无需使用不同的表每个用户类型。

然后,当您AddIdentity<ApplicationUser, IdentityRole>时,可以注册addIdentity(目前是这样),然后注入ApplicationUser,这将获得用户类型。

答案 4 :(得分:0)

如果核心> = 3.0

services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<WorldContext>();