Identität mit mehreren Benutzertypen - DbContext-Design

8

Ich versuche, das Identitätspaket von .NET Core mit mehreren Klassen zu verwenden, die sich erweitern, IdentityUser<Guid>aber mit einer einzelnen UserRoleKlasse.

Ich habe mehrere Klassen, die UserStore<T>für jeden Benutzertyp erweitert werden, und eine einzelne Klasse, die erweitert wird RoleStore<UserRole>.

Das Folgende ist mein startup.cs :

services.AddIdentity<InternalUser, UserRole>(IdentityOptions)
    .AddDefaultTokenProviders()
    .AddUserStore<InternalUserStore>()
    .AddRoleStore<GenericUserRoleStore>();

services.AddIdentityCore<Contractor>(IdentityOptions)
    .AddRoles<UserRole>()
    .AddDefaultTokenProviders()
    .AddUserStore<ContractorUserStore>()
    .AddRoleStore<GenericUserRoleStore>();

services.AddIdentityCore<Homeowner>(IdentityOptions)
    .AddRoles<UserRole>()
    .AddDefaultTokenProviders()
    .AddUserStore<HomeownerUserStore>()
    .AddRoleStore<GenericUserRoleStore>();

Mein DbContexterstreckt sich nichtIdentityDbContext :

public sealed class EntityDbContext: DbContext { }

Ich habe mehrere Fehler erhalten, daher habe ich Folgendes hinzugefügt DbContext aber ich habe es auskommentiert:

public DbSet<IdentityUserClaim<Guid>> UserClaims { get; set; }

public DbSet<IdentityUserRole<Guid>> UserRoles { get; set; }

Ich bekomme viele verschiedene Fehler:

Build-Fehler für Instanz 'Dal.IdentityStores.InternalUserStore' für PluginType IUserStore - und Instanz 'RoleManager' für PluginType Microsoft.AspNetCore.Identity.RoleManager 1[Models.Entities.Users.UserRole] - and Instance 'Dal.IdentityStores.GenericUserRoleStore' for PluginType Microsoft.AspNetCore.Identity.IRoleStore1 [Models.Entities.Users.UserRole] - und Instanz 'Dal.IdentityStores PluginType Microsoft.AspNetCore.Identity.IRoleStore 1[Models.Entities.Users.UserRole] - and Instance 'Dal.IdentityStores.ContractorUserStore' for PluginType Microsoft.AspNetCore.Identity.IUserStore1 [Models.Entities.Contractors.Contractor] - und Instanz 'UserClaimsPrincipalFactory' für PluginType Microsoft.AspNetCore.Identity.IUserClaimsPrincipalFactory 1[Models.Entities.Contractors.Contractor] - and Instance 'UserClaimsPrincipalFactory<Contractor, UserRole>' for PluginType Microsoft.AspNetCore.Identity.IUserClaimsPrincipalFactory1 [Models.Entities.Cont PluginType Microsoft.AspNetCore.Identity.UserManager 1[Models.Entities.Homeowners.Homeowner] - and Instance 'UserClaimsPrincipalFactory<Homeowner>' for PluginType Microsoft.AspNetCore.Identity.IUserClaimsPrincipalFactory1 [Models.Entities.Homeowners.Homeowner]

Dies ist der Link zu meinem Repo

Node.JS
quelle
Also, was ist deine Frage?
Vano Maisuradze
Mein Code funktioniert nicht. Ich erhalte den obigen Fehler. Wie kann ich das Problem beheben, indem ich mehrere Typen als "Benutzer" verwende?
Node.JS
Ich habe dein Repo geklont und es hat bei mir funktioniert, also ist es wahrscheinlich dein Umweltproblem.
Vano Maisuradze
1
@VanoMaisuradze Versuchen Sie, einen Benutzer zu erstellen und sich anzumelden. Sie werden das Problem sehen. Es gibt einen Controller für die Registrierung / Anmeldung
Node.JS
1
Ja, habe ich. Vielen Dank
Node.JS

Antworten:

2

Ich habe Ihr Problem reproduziert und unten finden Sie eine Lösung dafür, aber ich würde noch einmal darüber nachdenken, mehrere Tabellen für verschiedene Benutzerrollen zu erstellen.

Hier sind zwei Hauptgründe gegen mehrere Benutzertabellen:

  1. Wenn Sie den Benutzer anhand der ID suchen möchten (vorausgesetzt, Sie kennen die Rolle nicht), müssen Sie mehrere Abfragen für verschiedene Tabellen ausführen, was die Leistung verringert und die Komplexität des Codes erhöht.
  2. Dies kann auch die Datenbankkomplexität erhöhen, da Sie mehrere Fremdschlüssel für andere Tabellen festlegen müssen.

Falls Sie immer noch mehrere Tabellen für verschiedene Benutzerrollen haben möchten, finden Sie hier einen kleinen "Hack". Sie müssen nur die OnModelCreating- Methode überschreiben und Entitäten konfigurieren:

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        builder.Entity<Contractor>(b =>
        {
            b.HasMany<IdentityUserRole<Guid>>().WithOne().HasForeignKey(ur => ur.UserId).IsRequired();
        });

        builder.Entity<UserRole>(b =>
        {
            b.HasKey(r => r.Id);
            b.HasIndex(r => r.NormalizedName).HasName("RoleNameIndex").IsUnique();
            b.ToTable("AspNetRoles");
            b.Property(r => r.ConcurrencyStamp).IsConcurrencyToken();

            b.Property(u => u.Name).HasMaxLength(256);
            b.Property(u => u.NormalizedName).HasMaxLength(256);

            b.HasMany<IdentityUserRole<Guid>>().WithOne().HasForeignKey(ur => ur.RoleId).IsRequired();
            b.HasMany<IdentityRoleClaim<Guid>>().WithOne().HasForeignKey(rc => rc.RoleId).IsRequired();
        });

        builder.Entity<IdentityRoleClaim<Guid>>(b =>
        {
            b.HasKey(rc => rc.Id);
            b.ToTable("AspNetRoleClaims");
        });

        builder.Entity<IdentityUserRole<Guid>>(b =>
        {
            b.HasKey(r => new { r.UserId, r.RoleId });
            b.ToTable("AspNetUserRoles");
        });

        builder.Entity<UserRole>().ToTable("Roles");
        builder.Entity<IdentityUserRole<Guid>>().ToTable("UserRoles");
        builder.Entity<IdentityRoleClaim<Guid>>().ToTable("RoleClaims");
        builder.Entity<IdentityUserClaim<Guid>>().ToTable("UserClaims");
    }

Danach sollten Sie sich anmelden können.

Vano Maisuradze
quelle
0

Basierend auf den Anforderungen, die das OP in den Kommentaren erläutert hat, und der Aussage, dass das OP keine Erfahrung im Datenbankdesign hat, werde ich versuchen, eine Antwort zu geben, die hoffentlich dazu beiträgt, das Leben der Projekt- und Softwareentwicklungskarriere des OP zu erleichtern:

Zunächst möchten Sie eine einzelne "Benutzer" -Tabelle:

|---------------------|------------------|------------------|
|      FirstName      |     LastName     |       Role       |
|---------------------|------------------|------------------|
|          Joe        |       Black      |     Contractor   |
|---------------------|------------------|------------------|

Sie haben weder Anforderungen für mehrere Benutzertabellen für das Projekt, noch würde ein Projekt oder Softwareprodukt im Allgemeinen so etwas erfordern. Wenn / WENN eine Benutzertabelle auf N Milliarden von Datensätzen skaliert wird, wird sie für die Leistung über Partitionen verteilt und / oder für Lese- und Schreibvorgänge denormalisiert, aber es handelt sich logischerweise immer noch um eine Tabelle in vielen skalierten komplexen Softwaresystemdesigns.

Sie geben an:

Wie kann ich verschiedene Benutzermetadaten für verschiedene Benutzertypen haben? Ein Bauunternehmer hat seine eigenen Immobilien, ein Hausbesitzer hat seine eigenen Immobilien usw. Ich möchte keinen riesigen Tisch mit allen möglichen Immobilien haben

Ihre Sorge ist, dass Sie nicht mit einem riesigen Tisch enden. Kurz gesagt, dies ist für Sie kein Problem. Sie haben noch keine Riesentabelle und wenn Sie 30 Spalten ("Eigenschaften", wie Sie sagten) hinzugefügt hätten, wäre dies KEINE Riesentabelle.

Erstellen Sie eine einzelne Benutzertabelle. Fügen Sie nullbare Spalten für die spezifischen Auftragnehmer-Eigenschaften und nullbare Spalten für die spezifischen Hausbesitzer-Eigenschaften hinzu. Machen Sie die Spalten nicht null, wenn die Eigenschaft für alle Benutzer gilt.

Eine Spalte, die für alle Benutzer gilt, ist die Rollenspalte für Ihre Benutzer. Sie haben also eine nicht nullbare Spalte mit dem Namen "Rolle".

Hinweis: Wenn Sie eine relationale Datenbank verwenden, müssen Sie keine Rollentabelle erstellen, die die Rollenzeilendatensätze enthält. Sie können dies tun, und Ihr Kursleiter kann dies erwarten. Sie können jedoch auch eine Klasse oder Aufzählung für konstante Zeichenfolgen in Ihrem Backend erstellen, die die möglichen Rollen darstellt und eine Form der Persistenz darstellt, die Integrität für diese Rollen bietet. Ich erwähne dies, weil dies ein Bereich ist, in dem Entwickler beim relationalen Datenbankdesign schnell in den Overkill der referenziellen Integrität geraten.

Brian Ogden
quelle
1
Entschuldigung, aber Ihre Antwort ist ein Vorschlag, den ich bereits gemacht habe. Dies beantwortet die Frage von OP nicht direkt. Auch das Erstellen von nullbaren Spalten ist möglicherweise keine gute Lösung. Zum Beispiel könnte die Verwendung von Json viel sauberer sein.
Vano Maisuradze
Nein, es ist ein bisschen mehr als ein Vorschlag, es ist ein höflich formulierter richtiger Weg, um die Lösung anzugehen und umzusetzen.
Brian Ogden