首页 文章

如何在ASP.NET MVC中使用自定义属性扩展Identity?

提问于
浏览
5

我似乎与身份有仇恨/爱情关系 . 我喜欢它,因为它是大多数应用程序的完整解决方案 . 但我讨厌它,因为扩展并不是一件容易的事 . 我觉得它比它应该更加复杂 .

我试图将自定义属性和外键添加到我的用户模型,但这似乎是一项非常困难的任务 .

我需要添加一个名为 UserId 的新 Identity 字段,因为Id是一个字符串,将由数据库自动生成 . 然后,我需要将一个外键添加到 Company 模型,另一个添加到 Location 模型 .

我按照answer from this other question中的说明尝试添加两个新的外键,并能够从我的控制器中获取它们的值 .

这是我到目前为止所做的 . 我修改后的 ApplicationUser 课程看起来像这样

public class ApplicationUser : IdentityUser
{
    [Key]
    public int MyUserId { get; set; }

    [ForeignKey("Company")]
    public int CompanyId { get; set; }

    [ForeignKey("Location")]
    public int CurrentLocationId { get; set; }

    public virtual Company Company { get; set; }

    public virtual Location Location { get; set; }

    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        // Add custom user claims here

        userIdentity.AddClaim(new Claim("MyUserId", this.MyUserId.ToString() ));

        userIdentity.AddClaim(new Claim("CompanyId", this.CompanyId.ToString() ));

        userIdentity.AddClaim(new Claim("CurrentLocationId", this.CurrentLocationId.ToString()));

        return userIdentity;
    }
}

我还创建了一个扩展类,允许我从控制器中获取值,如此

public static class IdentityExtensions
{
    public static int GetComapnyId(this IIdentity identity)
    {
        var claim = ((ClaimsIdentity)identity).FindFirst("ComapnyId");
        // Test for null to avoid issues during local testing
        return (claim != null) ? Int32.Parse(claim.Value) : 0;
    }

    public static int GetCurrentLocationId(this IIdentity identity)
    {
        var claim = ((ClaimsIdentity)identity).FindFirst("CurrentLocationId");
        // Test for null to avoid issues during local testing
        return (claim != null) ? Int32.Parse(claim.Value) : 0;
    }


    public static int GetMyUserId(this IIdentity identity)
    {
        var claim = ((ClaimsIdentity)identity).FindFirst("MyUserId");
        // Test for null to avoid issues during local testing
        return (claim != null) ? Int32.Parse(claim.Value) : 0;
    }

}

但是当我尝试添加新的迁移时,我遇到了“下面列出的”错误

这是错误

在模型生成期间检测到一个或多个验证错误:

ApplicationUser_Claims_Source_ApplicationUser_Claims_Target ::参照约束的从属角色中的所有属性的类型必须与主体角色中的相应属性类型相同 . 实体'IdentityUserClaim'上的属性'MyUserId'的类型与引用约束'ApplicationUser_Claims'中实体'ApplicationUser'上的属性'MyUserId'的类型不匹配 . ApplicationUser_Logins_Source_ApplicationUser_Logins_Target ::参照约束的从属角色中的所有属性的类型必须与主体角色中的相应属性类型相同 . 实体'IdentityUserLogin'上的属性'MyUserId'的类型与引用约束'ApplicationUser_Logins'中实体'ApplicationUser'上的属性'MyUserId'的类型不匹配 . ApplicationUser_Roles_Source_ApplicationUser_Roles_Target ::参照约束的从属角色中的所有属性的类型必须与主体角色中的相应属性类型相同 . 实体'IdentityUserRole'上的属性'MyUserId'的类型与参照约束'ApplicationUser_Roles'中实体'ApplicationUser'上的属性'MyUserId'的类型不匹配 .

这是我用来创建 InitialCreate 迁移的命令

Add-Migration InitialCreate

如何添加我的外键并能够正确地从控制器获取它们?

1 回答

  • 0

    Identity有一种方法可以将主键(Id字段)更改为 int . 这是很多样板/空类,但它适用于我们 . 也许这会有所帮助?

    public class ApplicationUser : IdentityUser<int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
    {
        [ForeignKey("Company")]
        public int CompanyId { get; set; }
    
        [ForeignKey("Location")]
        public int CurrentLocationId { get; set; }
    
        public virtual Company Company { get; set; }
    
        public virtual Location Location { get; set; }
    
        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
        {
            // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
            var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
            // Add custom user claims here
    
            userIdentity.AddClaim(new Claim("CompanyId", this.CompanyId.ToString() ));
    
            userIdentity.AddClaim(new Claim("CurrentLocationId", this.CurrentLocationId.ToString()));
    
            return userIdentity;
        }
    }
    
    public class ApplicationUserLogin : IdentityUserLogin<int>
    {
    }
    
    public class ApplicationUserRole : IdentityUserRole<int>
    {
        [ForeignKey("RoleId")]
        public virtual ApplicationRole Role { get; set; }
    
        [ForeignKey("UserId")]
        public virtual ApplicationUser User { get; set; }
    }
    
    public class ApplicationRole : IdentityRole<int, UserRole>
    {
    
    }
    
    public class ApplicationUserClaim : IdentityUserClaim<int>
    {
    }
    

    那么我们也需要一个自定义 ApplicationUserStore

    public class ApplicationUserStore : UserStore<ApplicationUser, ApplicationRole, int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
    {
        public ApplicationUserStore(DbContext context)
            : base(context)
        {
        }
    }
    

相关问题