【问题标题】:How can I extend Identity with custom attributes in ASP.NET MVC?如何在 ASP.NET MVC 中使用自定义属性扩展 Identity?
【发布时间】:2016-10-13 05:40:21
【问题描述】:

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

我正在尝试向我的用户模型添加自定义属性和外键,但这似乎是一项非常困难的任务。

我需要添加一个名为 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: : 引用的从属角色中所有属性的类型 约束必须与相应的属性类型相同 主要角色。实体上的属性“MyUserId”的类型 “IdentityUserClaim”与属性“MyUserId”的类型不匹配 引用约束中的实体“ApplicationUser” 'ApplicationUser_Claims'。 ApplicationUser_Logins_Source_ApplicationUser_Logins_Target: : 引用的从属角色中所有属性的类型 约束必须与相应的属性类型相同 主要角色。实体上的属性“MyUserId”的类型 “IdentityUserLogin”与属性“MyUserId”的类型不匹配 引用约束中的实体“ApplicationUser” 'ApplicationUser_Logins'。 ApplicationUser_Roles_Source_ApplicationUser_Roles_Target: : 类型 引用约束的从属角色中的所有属性 必须与 Principal 中对应的属性类型相同 角色。实体“IdentityUserRole”上的属性“MyUserId”的类型确实 与实体“ApplicationUser”上的属性“MyUserId”类型不匹配 引用约束“ApplicationUser_Roles”。

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

Add-Migration InitialCreate

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

【问题讨论】:

  • 你是如何定义IdentityUserClaim的?
  • 我真的认为最好将身份和其他实体保持在不同的上下文中。身份有一个UserId,您可以稍后使用它从您的主上下文加载您的用户。
  • @GertArnold 我没有对我的IdentityUserClaim进行任何更改@
  • @AdrianIftode 我没有关注你。我在这里要做的就是向我的应用程序中的其他模型添加外键
  • 我理解并且我建议采用不同的方法。将身份与自己的上下文一起使用,并将模型放在您自己的上下文中。您始终可以使用该扩展方法访问 UserId 并像往常一样加载 User + Company 和 Location。

标签: c# asp.net-mvc entity-framework asp.net-mvc-5 identity


【解决方案1】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-08
    相关资源
    最近更新 更多