Відокремлення ASP.NET IdentityUser від інших моїх сутностей


11

У мене є ProjectName.Coreбібліотека, яка містить всю мою ділову логіку та мої сутності та їх поведінку. Зараз немає жодного відношення до Entity Framework або будь-якого іншого DAL, тому що мені подобається тримати ці речі відокремленими. Конфігурації Entity Framework (за допомогою API Fluent) знаходяться в ProjectName.Infrastructureпроекті, що забезпечує можливість просування моїх сутностей у EF. В основному я йду в напрямку архітектури, що нагадує цибулю.

Однак, додаючи рамку ідентичності ASP.NET в суміш, я повинен зробити свою ApplicationUserсутність у спадок від IdentityUserкласу, але мій ApplicationUserклас має стосунки з іншими сутностями. В спадщину від проекту IdentityUserя ввожу посилання на Entity Framework у проекті моїх сутностей - єдине місце, де я б не хотів цього робити. Витягнення ApplicationUserкласу з проекту сутності та в Infrastructureпроект (оскільки він використовує систему ідентичності, заснований на Entity Framework) призведе до кругових посилань, так що це не шлях.

Чи є якийсь спосіб цього, щоб я міг зберегти чисту поділ між двома шарами, окрім того, що не використовую ідентичність ASP.NET?


1
Чи не можете ви створити інтерфейс IApplicationUser у своєму проекті Core та зберегти реалізацію в інфраструктурі? На мою думку, якщо ви не створюєте API чи вам не потрібно обмінюватися реалізацією інтерфейсу під час виконання, просто зберігайте всі свої коди без інтерфейсу в одному проекті. Маючи купу різних проектів, просто додає вашим розумовим управлінням та керуванням кодами без особливої ​​користі.
mortalapeman

Відповіді:


12

Ви можете створити клас користувача , який не має нічого спільного з ASP.NET Identity у вашій основній бібліотеці.

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; }
}

Якщо ви використовуєте Entity Framework, створіть клас конфігурації для ваших організацій (необов'язково).

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);
    }
}

Вам також доведеться створити класи для ролей, UserClaim та UserLogin . Ви можете назвати їх, що завгодно, якщо вам не подобаються вищевказані імена.

У веб-шарі створіть клас під назвою AppUser (Або інше ім'я, якщо ви бажаєте). Цей клас повинен реалізувати інтерфейс ASP.NET Identity IUser <TKey> , де TKey - тип даних для первинного ключа ( Посібник у наведеному вище прикладі).

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; }
}

Змініть усі посилання на UserManager у веб-проекті на UserManager <AppUser, Guid> .

Нарешті, створіть власний UserStore . За суті, звичай UserStore буде приймати в AppUser об'єкт, перетворити його в користувача об'єкта суті, а потім зберігаються його. Приклад одного з цих методів наведено нижче:

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
}

Щоб отримати повний опис можливої ​​реалізації, натисніть тут .

Зрештою, це ваш вибір. Виміряйте кількість зусиль, необхідного для підтримання цієї реалізації, а не просто посилання на рамки Identity у вашій основній бібліотеці. Особисто я думав зробити це так, як я описав вище, однак я цього не зробив, тому що потенційно мені доведеться міняти свій код щоразу, коли рамки ASP.NET Identity оновлюються.

Сподіваємось, це допомагає і відповідає на ваше запитання!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.