Separazione di ASP.NET IdentityUser dalle altre mie entità

11

Ho una libreria ProjectName.Core contenente tutta la mia logica aziendale e le mie entità e il loro comportamento. Al momento non esiste alcun rapporto con Entity Framework o qualsiasi altro DAL perché mi piace mantenere le cose separate. Le configurazioni di Entity Framework (che utilizzano l'API Fluent) risiedono in un progetto ProjectName.Infrastructure in modo che si prenda cura di spingere le mie entità in EF. Fondamentalmente sto andando nella direzione di un'architettura simile a Onion.

Tuttavia, quando aggiungo il framework Identity ASP.NET nel mix, devo rendere ereditata la mia entità ApplicationUser dalla classe IdentityUser ma la mia classe ApplicationUser ha relazioni con altre entità. In ereditando da IdentityUser sto introducendo un riferimento a Entity Framework nel mio progetto entità, l'unico posto dove non vorrei farlo. Se si estrae la classe ApplicationUser dal progetto entità e nel progetto Infrastructure (poiché utilizza un sistema di identità basato su Entity Framework) si otterranno riferimenti circolari, quindi non è il modo di procedere.

C'è un modo per aggirare questo, così posso mantenere la separazione tra i due livelli oltre a non utilizzare l'identità di ASP.NET?

    
posta Steven Thewissen 17.03.2015 - 19:32
fonte

1 risposta

11

Puoi creare una classe Utente che non ha nulla a che fare con ASP.NET Identity nella tua libreria principale.

public class User {
    public Guid UserId { get; set; }
    public string UserName { get; set; }
    public string EmailAddress { get; set; }
    public string EmailAddressConfirmed { get; set; }
    public string PhoneNumber { get; set; }
    public string PhoneNumberConfirmed { get; set; }
    public string PasswordHash { get; set; }
    public string SecurityStamp { get; set; }

    ...

    public virtual ICollection<Role> Roles { get; set; }
    public virtual ICollection<UserClaim> UserClaims { get; set; }
    public virtual ICollection<UserLogin> UserLogins { get; set; }
}

Se stai utilizzando Entity Framework, crea una classe di configurazione per le tue entità (facoltativo).

internal class UserConfiguration : EntityTypeConfiguration<User>
{
    internal UserConfiguration()
    {
        ToTable("User");

        HasKey(x => x.UserId)
            .Property(x => x.UserId)
            .HasColumnName("UserId")
            .HasColumnType("uniqueidentifier")
            .IsRequired();

        Property(x => x.PasswordHash)
            .HasColumnName("PasswordHash")
            .HasColumnType("nvarchar")
            .IsMaxLength()
            .IsOptional();

        Property(x => x.SecurityStamp)
            .HasColumnName("SecurityStamp")
            .HasColumnType("nvarchar")
            .IsMaxLength()
            .IsOptional();

        Property(x => x.UserName)
            .HasColumnName("UserName")
            .HasColumnType("nvarchar")
            .HasMaxLength(256)
            .IsRequired();

        // EmailAddress, PhoneNumber, ...

        HasMany(x => x.Roles)
            .WithMany(x => x.Users)
            .Map(x =>
            {
                x.ToTable("UserRole");
                x.MapLeftKey("UserId");
                x.MapRightKey("RoleId");
            });

        HasMany(x => x.UserClaims)
            .WithRequired(x => x.User)
            .HasForeignKey(x => x.UserId);

        HasMany(x => x.UserLogins)
            .WithRequired(x => x.User)
            .HasForeignKey(x => x.UserId);
    }
}

Dovresti anche creare classi per Role, UserClaim e UserLogin . Puoi nominarli come preferisci se non ti piacciono i nomi di cui sopra.

Nel livello web, crea una classe chiamata AppUser (o un altro nome se lo desideri). Questa classe deve implementare l'interfaccia ASP.NET Identity IUser < TKey > , dove TKey è il tipo di dati per la chiave primaria ( Guida nel esempio precedente).

public class AppUser : IUser<Guid>
{
    public AppUser()
    {
        this.Id = Guid.NewGuid();
    }

    public AppUser(string userName)
        : this()
    {
        this.UserName = userName;
    }

    public Guid Id { get; set; }
    public string UserName { get; set; }
    public string EmailAddress { get; set; }
    public string EmailAddressConfirmed { get; set; }
    public string PhoneNumber { get; set; }
    public string PhoneNumberConfirmed { get; set; }
    public string PasswordHash { get; set; }
    public string SecurityStamp { get; set; }
}

Cambia tutti i riferimenti a UserManager nel progetto web su UserManager < AppUser, Guida > .

Infine, crea il tuo UserStore . In sostanza, lo UserStore personalizzato includerà l'oggetto AppUser , convertendolo in un oggetto entità Utente , quindi lo conserverà. Di seguito è riportato un esempio di uno di questi metodi:

public class UserStore : 
    IUserLoginStore<AppUser, Guid>, 
    IUserClaimStore<AppUser, Guid>, 
    IUserRoleStore<AppUser, Guid>, 
    IUserPasswordStore<AppUser, Guid>, 
    IUserSecurityStampStore<AppUser, Guid>, 
    IUserStore<AppUser, Guid>, 
    IDisposable
{
    private User MapFromAppUser(AppUser appUser)
    {
        if (appUser == null)
            return null;

        var userEntity = new User();

        PopulateUser(userEntity, appUser);

        return userEntity;
    }

    private void PopulateUser(User user, AppUser appUser)
    {
        user.UserId = appUser.Id;
        user.UserName = appUser.UserName;
        user.EmailAddress = appUser.EmailAddress;
        user.EmailAddressConfirmed = appUser.EmailAddressConfirmed;
        user.PhoneNumber = appUser.PhoneNumber;
        user.PhoneNumberConfirmed = appUser.PhoneNumberConfirmed;
        user.PasswordHash = appUser.PasswordHash;
        user.SecurityStamp = appUser.SecurityStamp;

        // First name, last name, ... 
    }

    #region IUserStore<AppUser, Guid> Members

    public Task CreateAsync(AppUser appUser)
    {
        if (appUser == null)
            throw new ArgumentNullException("appUser");

        var userEntity = MapFromAppUser(appUser);

        // Persist the user entity to database using a data repository.
        // I'll leave this to you.
    }

    ...

    #endregion
}

Per ottenere una descrizione completa di una possibile implementazione, fai clic su qui .

Alla fine, è la tua scelta. Misura la quantità di sforzi che occorrerebbe per mantenere questa implementazione rispetto al semplice riferimento al framework Identity nella tua libreria Core. Personalmente, ho pensato di farlo nel modo in cui ho descritto sopra, tuttavia, non l'ho fatto perché avrei potenzialmente dovuto cambiare il mio codice ogni volta che il framework Identity ASP.NET è stato aggiornato.

Speriamo che questo aiuti e risponda alla tua domanda!

    
risposta data 29.05.2015 - 06:51
fonte

Leggi altre domande sui tag