.net-core - .NET Core 标识多种用户类型

标签 .net-core asp.net-identity

我有多个类( ABC )每个扩展 IdentityUser<Guid> .我还有一个名为 UserRole 的类(class)延伸 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; }

}

我将身份添加到 IServiceCollection :

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

        // Same for B, C

我还有以下商店:

public class AUserStore : UserStore<A, UserRole, EntityDbContext, Guid> { } 
public class BUserStore : UserStore<B, UserRole, EntityDbContext, Guid> { } 
public class CUserStore : UserStore<C, UserRole, EntityDbContext, Guid> { } 

以下是我遇到的错误:

Specified argument was out of the range of valid values. (Parameter 'instance 'AUserStore' with ReturnType AUserStore cannot be cast to 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>();

最佳答案

关于 AddIdentityAddIdentityCore 的评论都有这个:

Adds and configures the identity system for the specified User and Role types.

和,

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

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));
        services.AddIdentity<ApplicationUser, ApplicationRole>(options => options.SignIn.RequireConfirmedAccount = true)
            .AddEntityFrameworkStores<ApplicationDbContext>();
        ....
    }
    

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

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

  1. Inheritance with EF Code First: Part 1 – Table per Hierarchy (TPH)
  2. Inheritance with EF Code First: Part 2 – Table per Type (TPT)
  3. Inheritance with EF Code First: Part 3 – Table per Concrete Type (TPC)

您有 3 个以上的 normal 选项来映射您的任何 UserType 数据到数据库。第一个选项为您提供最佳性能,但当您的用户类型非常复杂时,它会给您带来非常困惑的 datatable 。您可以为您的实际项目选择其中一个作为平衡。

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

public class ApplicationUser : IdentityUser<int>
{
    public ApplicationUser() : base()
    {
        UserRoles = new HashSet<ApplicationUserRole>();
    }

    public int YearsOfExperience { get; set; }

    [InverseProperty("User")]
    public virtual ICollection<ApplicationUserRole> UserRoles { get; set; }
}


public class ProjectManager : ApplicationUser
{
    public bool Talktive { get; set; }
}

public class Developer : ApplicationUser
{
    public bool IsCSharper { get; set; }
}

public class Tester : Developer
{
    public bool WhiteBox { get; set; }
}

public class Documenter : Tester
{
    public List<string> Languages { get; set; } = new List<string>();
}


public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, int>
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }

    //get following users directly by following properties
    public DbSet<ProjectManager>  ProjectManagers { get; set; }
    public DbSet<Developer>  Developers { get; set; }
    public DbSet<Tester>  Testers { get; set; }
    public DbSet<Documenter>  Documenters { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        //prevent creating tables for following usertypes
        builder.Ignore<ProjectManager>();
        builder.Ignore<Developer>();
        builder.Ignore<Tester>();
        builder.Ignore<Documenter>();


        base.OnModelCreating(builder);

        builder.Entity<ApplicationUser>(entity =>
        {
            entity.HasMany(u => u.UserRoles).WithOne(x => x.User).HasForeignKey(c => c.UserId).IsRequired().OnDelete(DeleteBehavior.Cascade);

            //tell database to use this column as Discriminator
            entity.HasDiscriminator<string>("UserType");
        });

        builder.Entity<ApplicationRole>(entity =>
        {
            entity.HasKey(x => x.Id);
        });

        builder.Entity<ApplicationUserRole>(entity =>
        {
            entity.HasKey(c => new { c.UserId, c.RoleId });
            entity.HasOne(x => x.Role).WithMany(x => x.UserRoles).HasForeignKey(x => x.RoleId).IsRequired().OnDelete(DeleteBehavior.Cascade);
            entity.HasOne(x => x.User).WithMany(x => x.UserRoles).HasForeignKey(x => x.UserId).IsRequired().OnDelete(DeleteBehavior.Cascade);
        });
    }
}

当您需要用户时:

var allUsers = await _dbContext.Users.ToListAsync();
var allProjectManagers = await _dbContext.ProjectManagers.ToListAsync();
var allDevelopers = await _dbContext.Developers.ToListAsync();
var allTesters = await _dbContext.Testers.ToListAsync();

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

public class ApplicationUserManager<TUser, TRole>
    where TUser : ApplicationUser
    where TRole : ApplicationRole

{
    private readonly ApplicationDbContext _context;
    private readonly UserManager<TUser> _userManager;
    private readonly RoleManager<TRole> _roleManager;

    public ApplicationUserManager(ApplicationDbContext context,
        UserManager<TUser> userManager,
        RoleManager<TRole> roleManager)
    {
        _context = context;
        _userManager = userManager;
        _roleManager = roleManager;
    }
    //customize your own base logics here.

}

public class DeveloperUserManager : ApplicationUserManager<Developer, ApplicationRole>
{

}

public class DocumenterUserManager : ApplicationUserManager<Documenter, ApplicationRole>
{

}

好好享受吧。

关于.net-core - .NET Core 标识多种用户类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58848481/

相关文章:

kubernetes - 如何修复 “Tried to associate with unreachable remote address [akka.tcp://actorsystem@address:port]”错误?

visual-studio-2013 - 我可以在Visual Studio 2013上使用.net Core吗

c# - 使用 Entity Framework Core、npgsql、PostgreSQL 创建新数据库

asp.net - Entity Framework 代码优先 - 无效的列名 'Discriminator1'

asp.net-mvc - Asp.Net MVC 6 身份 3 MongoDB 外部登录 (Facebook)

c# - PasswordHasher 方法的用户参数有什么用?

c# - 将文档添加到 Azure Cosmos DB 时缺少属性

asp.net-core - Blazor 独立 WebAssembly 代表登录用户调用安全核心 API

asp.net-mvc - 从 ASP.NET Identity 2.x 中的角色中删除用户

c# - 从已发送的电子邮件网络核心身份调用时,重置密码不起作用