.NET Core 标识多种用户类型

Nod*_*.JS 4 asp.net-identity .net-core

我有多个类(ABC,每个类都扩展IdentityUser<Guid>。我还有一个名为UserRolewhich extends 的类IdentityRole<Guid>

以下是我的DbContext

public sealed class EntityDbContext: DbContext
{
    public DbSet<A> As { get; set; }

    public DbSet<B> Bs { get; set; }

    public DbSet<C> Cs { get; set; }

}
Run Code Online (Sandbox Code Playgroud)

我将身份添加到IServiceCollection

        services
            .AddIdentityCore<A>()
            .AddEntityFrameworkStores<EntityDbContext>()
            .AddRoles<UserRole>()
            .AddUserStore<AUserStore>()
            // .AddRoleStore<TRoleStore>()
            .AddDefaultTokenProviders();

        // Same for B, C
Run Code Online (Sandbox Code Playgroud)

我还有以下商店:

public class AUserStore : UserStore<A, UserRole, EntityDbContext, Guid> { } 
public class BUserStore : UserStore<B, UserRole, EntityDbContext, Guid> { } 
public class CUserStore : UserStore<C, UserRole, EntityDbContext, Guid> { } 
Run Code Online (Sandbox Code Playgroud)

以下是我收到的错误:

指定的参数超出了有效值的范围。(返回类型为 AUserStore 的参数“实例 'AUserStore' 无法转换为 IUserStore”)

我不知道我正在做的事情是否可行。感谢您的任何帮助或提示。


更新

我想我已经成功了:

class GenericUserRoleStore : RoleStore<UserRole, EntityDbContext, Guid> { }

        services.AddIdentity<A, UserRole>()
            .AddDefaultTokenProviders()
            .AddUserStore<AUserStore>()
            .AddRoleStore<GenericUserRoleStore>();

        services.AddIdentityCore<B>()
            .AddRoles<UserRole>()
            .AddDefaultTokenProviders()
            .AddUserStore<BUserStore>()
            .AddRoleStore<GenericUserRoleStore>();

        services.AddIdentityCore<C>()
            .AddRoles<UserRole>()
            .AddDefaultTokenProviders()
            .AddUserStore<CUserStore>()
            .AddRoleStore<GenericUserRoleStore>();
Run Code Online (Sandbox Code Playgroud)

Don*_*ong 5

AddIdentity两者都有这样的评论AddIdentityCore

\n\n
\n

为指定的用户和角色类型添加和配置身份系统。

\n
\n\n

和,

\n\n
    \n
  1. 比较AddIdentity<>AddIdentityCore<>的源代码,
  2. \n
  3. 查看项目模板中的默认代码:

    \n\n
    public void ConfigureServices(IServiceCollection services)\n{\n    services.AddDbContext<ApplicationDbContext>(options =>\n        options.UseSqlServer(\n            Configuration.GetConnectionString("DefaultConnection")));\n    services.AddIdentity<ApplicationUser, ApplicationRole>(options => options.SignIn.RequireConfirmedAccount = true)\n        .AddEntityFrameworkStores<ApplicationDbContext>();\n    ....\n}\n
    Run Code Online (Sandbox Code Playgroud)
  4. \n
\n\n

我想说:当您向 IdentityFramework 注册多个身份类型时,它会感到困惑,但我们确实需要它。

\n\n

我相信您正在寻找的是这些帖子:

\n\n
    \n
  1. 使用 EF Code First 进行继承:第 1 部分 \xe2\x80\x93 每个层次结构表 (TPH)
  2. \n
  3. 使用 EF Code First 进行继承:第 2 部分 \xe2\x80\x93 每个类型的表 (TPT)
  4. \n
  5. 使用 EF Code First 进行继承:第 3 部分 \xe2\x80\x93 每个具体类型的表 (TPC)
  6. \n
\n\n

您可以通过以上 3 个normal选项将map任何UserType数据保存到数据库。第一个选项为您提供最佳性能,但当datatable您的用户类型非常复杂时,会给您带来非常混乱的情况。您可以为您的实际项目选择其中任何一个作为平衡。

\n\n

这是第一种方法的示例代码:

\n\n
public class ApplicationUser : IdentityUser<int>\n{\n    public ApplicationUser() : base()\n    {\n        UserRoles = new HashSet<ApplicationUserRole>();\n    }\n\n    public int YearsOfExperience { get; set; }\n\n    [InverseProperty("User")]\n    public virtual ICollection<ApplicationUserRole> UserRoles { get; set; }\n}\n\n\npublic class ProjectManager : ApplicationUser\n{\n    public bool Talktive { get; set; }\n}\n\npublic class Developer : ApplicationUser\n{\n    public bool IsCSharper { get; set; }\n}\n\npublic class Tester : Developer\n{\n    public bool WhiteBox { get; set; }\n}\n\npublic class Documenter : Tester\n{\n    public List<string> Languages { get; set; } = new List<string>();\n}\n\n\npublic class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, int>\n{\n    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)\n        : base(options)\n    {\n    }\n\n    //get following users directly by following properties\n    public DbSet<ProjectManager>  ProjectManagers { get; set; }\n    public DbSet<Developer>  Developers { get; set; }\n    public DbSet<Tester>  Testers { get; set; }\n    public DbSet<Documenter>  Documenters { get; set; }\n\n    protected override void OnModelCreating(ModelBuilder builder)\n    {\n        //prevent creating tables for following usertypes\n        builder.Ignore<ProjectManager>();\n        builder.Ignore<Developer>();\n        builder.Ignore<Tester>();\n        builder.Ignore<Documenter>();\n\n\n        base.OnModelCreating(builder);\n\n        builder.Entity<ApplicationUser>(entity =>\n        {\n            entity.HasMany(u => u.UserRoles).WithOne(x => x.User).HasForeignKey(c => c.UserId).IsRequired().OnDelete(DeleteBehavior.Cascade);\n\n            //tell database to use this column as Discriminator\n            entity.HasDiscriminator<string>("UserType");\n        });\n\n        builder.Entity<ApplicationRole>(entity =>\n        {\n            entity.HasKey(x => x.Id);\n        });\n\n        builder.Entity<ApplicationUserRole>(entity =>\n        {\n            entity.HasKey(c => new { c.UserId, c.RoleId });\n            entity.HasOne(x => x.Role).WithMany(x => x.UserRoles).HasForeignKey(x => x.RoleId).IsRequired().OnDelete(DeleteBehavior.Cascade);\n            entity.HasOne(x => x.User).WithMany(x => x.UserRoles).HasForeignKey(x => x.UserId).IsRequired().OnDelete(DeleteBehavior.Cascade);\n        });\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

当您需要您的用户时:

\n\n
var allUsers = await _dbContext.Users.ToListAsync();\nvar allProjectManagers = await _dbContext.ProjectManagers.ToListAsync();\nvar allDevelopers = await _dbContext.Developers.ToListAsync();\nvar allTesters = await _dbContext.Testers.ToListAsync();\n
Run Code Online (Sandbox Code Playgroud)\n\n

接下来要配置的是 UserManager,而不是 IUserStore。

\n\n
public class ApplicationUserManager<TUser, TRole>\n    where TUser : ApplicationUser\n    where TRole : ApplicationRole\n\n{\n    private readonly ApplicationDbContext _context;\n    private readonly UserManager<TUser> _userManager;\n    private readonly RoleManager<TRole> _roleManager;\n\n    public ApplicationUserManager(ApplicationDbContext context,\n        UserManager<TUser> userManager,\n        RoleManager<TRole> roleManager)\n    {\n        _context = context;\n        _userManager = userManager;\n        _roleManager = roleManager;\n    }\n    //customize your own base logics here.\n\n}\n\npublic class DeveloperUserManager : ApplicationUserManager<Developer, ApplicationRole>\n{\n\n}\n\npublic class DocumenterUserManager : ApplicationUserManager<Documenter, ApplicationRole>\n{\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

好好享受。

\n