在 MVC 中对我自己的实体使用 ASP.NET 身份

Using ASP.NET Identity with my own entities in MVC

在我的 "Car Hire" 解决方案中,我有一个单独的项目来保存我的所有实体,例如用户、角色、汽车、预订等。我正在使用 EntityFramework Code First 生成数据库。所有这些都工作正常。 我在我的解决方案中添加了一个 MVC 项目。现在我想充分利用 ASP.NET Identity 2.x 模型。 我的问题是:如何将 MVC 项目附带的 ApplicationUser 与我自己的用户 Class 合并? 我的用户 class:

public partial class User
{
    public User()
    {
    }
    [Key]
    public int Id { get; set; }
    [StringLength(200)]
    public string FirstName { get; set; }
    [StringLength(200)]
    public string LastName { get; set; }
    [StringLength(200)]
    public string Address1 { get; set; }
    [StringLength(200)]
    public string Address2 { get; set; }
    [StringLength(200)]
    public string Address3 { get; set; }
    [StringLength(20)]
    public string ZipCode { get; set; }
    [StringLength(200)]
    public string City { get; set; }
    [StringLength(200)]
    public string Country { get; set; }
    [StringLength(200)]
    public string Phone { get; set; }
    [StringLength(200)]
    public string MobilePhone { get; set; }
    [StringLength(200)]
    public string WorkPhone { get; set; }
}

我是否应该将所有用户属性移动到 ApplicationUser class 并在我自己的 class 中向 ApplicationUser 添加一个外键,例如 Booking class?

但是嘿,你能不能只从 ApplicationUser 到你的 User 模型做一个 link?

有时候像那样移动代码并不那么容易。如果是这种情况,您可以这样做:

public class ApplicationUser {
      public virtual YourUserModel userModel { get; set; }
}

希望对您有所帮助!

编辑: 或者,您可以像 Callum 所说的那样,让您的 User class 继承自 IdentityUser:

public class User : IdentityUser {
     //your properties here
}

这将是所有用户的基础class

public abstract class User : IdentityUser
{
    public abstract string Area { get; }
    public bool IsActiveDirectoryUser { get; private set; }

    protected User(string username, bool isActiveDirectoryUser = false)
        : base(username)
    {
        IsActiveDirectoryUser = isActiveDirectoryUser;
    }

    protected User()
    { }
}

这是用户的例子

public class AdminUser : User
{
    public AdminUser(string username, bool isActiveDirectoryUser = false)
        : base(username, isActiveDirectoryUser)
    { }

    private AdminUser()
    { }

    public override string Area
    {
        get { return UserAreas.Admin; }
    }
}

这是 DBContext,忽略用户的映射是 属性 因为它是硬编码的

    public class IdentityDataContext : IdentityDbContext<User>
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<User>().ToTable("AspNetUsers").Ignore(u => u.Area);
        modelBuilder.Entity<AdminUser>().ToTable("AdminUsers");
    }
}

这是您自定义的 IUserManager 实现。它在实体用户上工作,使用我们已经定义的 IdentityDataContext 和我们的自定义 ClaimsFactory(如果需要的话),如下所示

    public class UserManager
{
    private readonly UserManager<User> _identityManager;

    public UserManager(ClaimsFactory claimsFactory, IdentityDataContext context, IdentityValidator identityValidator)
    {
        _identityManager = new UserManager<User>(new UserStore<User>(context))
                           {
                               ClaimsIdentityFactory = claimsFactory,
                               UserValidator = identityValidator
                           };
    }

    public void Register(User user, string password)
    {
        var result = _identityManager.Create(user, password);

        if (!result.Succeeded)
            throw new ApplicationException("User can not be created. " + result.Errors.FirstOrDefault());
    }

    public void Register(User user)
    {
        var result = _identityManager.Create(user);

        if (!result.Succeeded)
            throw new ApplicationException("User can not be created. " + result.Errors.FirstOrDefault());
    }
    public User Find(string userName, string password)
    {
        return _identityManager.Find(userName, password);
    }

    public ClaimsIdentity CreateIdentity(User user, string applicationCookie)
    {
        return _identityManager.CreateIdentity(user, applicationCookie);
    }

    public User FindByUserName(string userName)
    {
        return _identityManager.FindByName(userName);
    }

    public bool ChangePassword(string identifier, string oldPassword, string newPassword)
    {
        return _identityManager.ChangePassword(identifier, oldPassword, newPassword).Succeeded;
    }

    public bool ResetPassword(string userName, string password)
    {
        try
        {
            var user = FindByUserName(userName);

            var result = _identityManager.RemovePassword(user.Id);

            if (result != IdentityResult.Success)
                return false;

            result = _identityManager.AddPassword(user.Id, password);

            return result == IdentityResult.Success;
        }
        catch (Exception)
        {
            return false;
        }
    }

    public User FindById(string userId)
    {
        return _identityManager.FindById(userId);
    }

    public bool IsInRole(string userId, string role)
    {
        return _identityManager.IsInRole(userId, role);
    }

    public void AddToRole(string userId, string role)
    {
        _identityManager.AddToRole(userId, role);
    }
}

如果您喜欢索赔,这就是索赔工厂。它将de user area转化为claim,最后转化为浏览器中的cookie。

    public class ClaimsFactory : ClaimsIdentityFactory<User>
{
    public async override Task<ClaimsIdentity> CreateAsync(UserManager<User> manager, User user, string authenticationType)
    {
        var identity = await base.CreateAsync(manager, user, authenticationType);

        identity.AddClaim(new Claim(ClaimTypes.Area, user.Area, ClaimValueTypes.String));

        return identity;
    }
}

ApplicationUser没什么特别的。它只是继承自 IdentityUser 的 class 的默认实现。即便如此,这种继承也只是 bootstrap Identity 中的所有功能,例如角色、声明等

您可以完全删除 ApplicationUser 并让您的用户 class 继承自 IdentityUser,或者您可以将属性从您的用户 class 移至 ApplicationUser 并删除您的用户 class。无论哪种方式,结果都是一样的。

而且,是的,您想在与 "user" 相关的 class 和任何 class 最终成为您的 "user" class。同样,ApplicationUser 并没有什么特别之处,所以如果您选择坚持这一点,您可以像项目中的任何其他 POCO 一样设置它,根据需要与其他实体建立关系。

有人建议从 ApplicationUser 继承您的用户 class,但我认为这不是个好主意。从用于身份的基础 "user" class 继承是有正当理由的,但在这里您处理的不是不同类型的用户,而是一种需要额外属性的用户类型。如果您无法访问基础 class 来修改它,那么继承实际上只是一种可以接受的实现方式。在这里,你做的。这是你的class;项目模板只是为您创建的。