다른 엔터티에서 ASP.NET IdentityUser 분리


11

나는 ProjectName.Core모든 비즈니스 로직과 엔티티 및 그들의 동작을 포함 하는 라이브러리를 가지고 있습니다. Entity Framework 또는 다른 DAL과는 아무런 관련이 없습니다. Fluent API를 사용하는 Entity Framework 구성은 ProjectName.Infrastructure프로젝트에 상주 하므로 내 엔터티를 EF로 푸시합니다. 기본적으로 나는 양파와 같은 아키텍처의 방향으로 가고 있습니다.

그러나 ASP.NET Identity 프레임 워크를 믹스에 추가 할 때 내 ApplicationUser엔터티를 IdentityUser클래스 에서 상속해야 하지만 ApplicationUser클래스는 다른 엔터티와 관계가 있습니다. 상속을 받고 IdentityUser싶지 않은 곳에서 엔티티 프로젝트에 Entity Framework에 대한 참조를 소개합니다. 잡아 당기는 ApplicationUser특정 회사의 프로젝트에서 그리고로 클래스를 Infrastructure그 중 하나를 이동하는 방법이되지 않도록 (그것이 엔티티 프레임 워크 기반의 아이덴티티 시스템을 사용하기 때문에) 프로젝트 것은, 순환 참조가 발생합니다.

ASP.NET ID를 사용하지 않고 두 계층 사이를 깨끗하게 분리 할 수 ​​있도록이 방법을 사용할 수 있습니까?


1
핵심 프로젝트에서 IApplicationUser 인터페이스를 작성하고 구현을 인프라에 유지할 수 없습니까? 제 생각에는 API를 만들거나 런타임에 인터페이스 구현을 교체 해야하는 경우가 아니라면 모든 비 UI 코드를 하나의 프로젝트에 보관하십시오. 다양한 프로젝트를 수행하면 많은 이점없이 정신 및 코드 관리 오버 헤드가 증가합니다.
mortalapeman

답변:


12

코어 라이브러리에서 ASP.NET Identity와 관련이없는 User 클래스를 만들 수 있습니다 .

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

Role, UserClaim 및 UserLogin 클래스도 만들어야 합니다. 위의 이름이 마음에 들지 않으면 원하는 이름을 지정할 수 있습니다.

웹 계층에서 AppUser (또는 원하는 경우 다른 이름) 라는 클래스를 만듭니다 . 이 클래스는 ASP.NET Identity IUser <TKey> 인터페이스를 구현해야합니다 . 여기서 TKey 는 기본 키의 데이터 유형입니다 ( 위 예의 Guid ).

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 오브젝트를 가져 와서 User 엔티티 오브젝트 로 변환 한 후 유지합니다. 이러한 방법 중 하나의 예는 다음과 같습니다.

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
}

가능한 구현에 대한 자세한 설명을 보려면 여기를 클릭 하십시오 .

결국, 그것은 당신의 선택입니다. Core 라이브러리에서 Identity 프레임 워크를 참조하는 것보다이 구현을 유지하는 데 드는 노력의 양을 측정하십시오. 개인적으로, 나는 위에서 설명한 방식으로 생각했지만 ASP.NET Identity 프레임 워크가 업데이트 될 때마다 코드를 변경해야하기 때문에하지 않았습니다.

희망적으로 이것은 귀하의 질문에 도움이되고 답변됩니다!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.