将ASP.NET IdentityUser与我的其他实体分开


11

我有一个ProjectName.Core库,其中包含我的所有业务逻辑以及我的实体及其行为。当前与Entity Framework或任何其他DAL没有任何关系,因为我喜欢将这些内容分开。实体框架配置(使用Fluent API)位于ProjectName.Infrastructure项目中,以便将实体推入EF。基本上,我会朝着类似洋葱的架构的方向发展。

但是,将ASP.NET Identity框架添加到组合中时,我必须使我的ApplicationUser实体从IdentityUser该类继承,但是我的ApplicationUser类与其他实体有关系。在继承时,IdentityUser我在实体项目中引入了对Entity Framework的引用,这是我不想这样做的地方。将ApplicationUser类从实体项目中拉出并放入Infrastructure项目中(因为它使用的是基于Entity Framework的身份系统)将导致循环引用,因此也不可行。

有没有什么办法可以解决,所以除了不使用ASP.NET Identity之外,我还可以保持两层之间的清晰分隔?


1
您是否不能在Core项目中创建IApplicationUser接口并将实现保留在基础架构中?我认为,除非您要创建API或需要在运行时交换接口实现,否则只需将所有非UI代码保留在一个项目中即可。拥有许多不同的项目只会增加您的思维和代码管理开销,而没有太多好处。
mortalapeman

Answers:


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创建类。如果您不喜欢上述名称,则可以随便命名。

在Web层中,创建一个名为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; }
}

将Web项目中对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
}

要获得可能实现的完整说明,请单击此处

最后,这是您的选择。评估仅需在核心库中引用Identity框架即可维护该实现所需的工作量。就我个人而言,我曾想过按照上面描述的方式进行操作,但是我没有这样做,因为每次ASP.NET Identity框架更新时,都可能不得不更改代码。

希望这可以帮助并回答您的问题!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.