我可以在asp.net MVC-5项目中的aspnet数据库中添加新的自定义表

时间:2017-05-15 01:18:20

标签: asp.net asp.net-mvc asp.net-mvc-5 asp.net-identity asp.net-identity-2

我有以下内容: -

  1. Visual Studio 2013。
  2. 我创建了一个新的asp.net MVC-5 Web项目。
  3. 该项目使用的是asp.net identity 2.2。
  4. 对于身份验证方法,我选择了“个人用户帐户”
  5. 此过程创建了一个名为aspnet-OurProjectNanme-number
  6. 的新数据库
  7. 在自动生成的数据库中,我有一个名为AspNetUSers的表,用于存储用户信息。
  8. 现在我正在建立一个ERP系统。在ERP系统内部,我想添加以下内容: -

    1. 一个名为“Asset”的表,用于存储资产信息。
    2. “资产”表格中有2列名为“CreatedBy”+“ModifiedBy”,应存储创建和修改资产项目的userId。
    3. 现在我不确定我需要如何实现这一目标?因为我需要在我的自定义表“Asset”和自动创建的“AspNetUsers”表之间添加一个外键。所以我可以在自动生成的数据库中添加我的自定义表“Asset”,并构建Asset.CreatedByAspNetUsers.Id之间的外键 ??

      • 如果答案是,那么如果我们想要升级我们的aspnet身份版本,这种关系将来会破裂吗?因为升级身份可能会导致创建新表或重命名现有表等。这可能会破坏Asset表和AspNetUsers表之间的关系?

      • 如果答案是否(我不应该在自动生成的数据库中添加自定义表)那么我如何构建外键?我需要在这种情况下添加资产表?

2 个答案:

答案 0 :(得分:4)

- 更新 -

答案正在增长和增长,discussion也是如此。我想我已经展示了各种各样的变化,这可能没有任何帮助使它变得可以理解。所以这是一个总结。有关解释,请阅读完整的答案和讨论。

开箱即用,你有两个背景,身份和业务。它们是分离的,因此您可以在不干扰业务的情况下更改安全性。这样,升级安全性不会破坏您的应用程序或其他模型。由于上下文是分开的,因此对其中任何一个的更改都不会影响另一个。

作为旁注:您无意直接访问AspNet身份表。实现UserManager并使用管理器的可用方法来执行操作。

现在谈到逻辑,应该在哪里存储信息?作为一个简单的规则,只要问自己一个问题:它是安全还是业务的一部分?

在这两种情况下,您都拥有用户。根据您的要求,这是一个逻辑1:1的关系。但它们实际上是分开的。您可以在不提供登录或删除登录的情况下创建人员,而无需删除用户(人员),例如由于历史原因。

您只需要查找当前用户的所有信息。所以你需要的只是People.Id。

无需更改IdentityUser,您只需覆盖AspNetUser.Id即可创建1:1关系。

var appUser = new IdentityUser
{
    UserName = model.Email,
    Email = model.Email,
    Id = Convert.ToString(People.Id)
};
var identityResult = await userManager.CreateAsync(appUser, model.Password);

您不需要业务的身份上下文。你需要的只是People.Id。只有在发出令牌并创建/修改用户时才使用身份上下文。

要获取id,请使用以下内容:

 var peopleId = int.Parse(Request.User.Identity.GetUserId());

现在,您可以使用Id。

查询您的商业模式

注册时,使用您要存储的人员信息扩展View和ViewModel。这将允许您同时添加People和AspNetUser。虽然这不是一个交易。但我认为,如果先执行检查,创建任何一个都不会失败。

您可以验证用户名和密码(使用UserManager中的方法)并在创建用户之前检查viewmodel的ModelState。使用属性强制填充必填字段。

- 原始答案 -

为了不重复自己,请阅读我的回答here

简而言之,保持身份和业务分离。 以防从同一数据库中删除标识逻辑,就像实现IdentityServer一样。

您似乎在AspNetUser中有业务信息。如果是这样,请创建一个Person表并将信息移动到该表。与模型中的该表相关联。在表Person中,您可以添加对AspNetUser的引用。

- 更新 -

我认为您理解正确,但我会在此答案中添加详细信息。

在大多数情况下,所有表都在一个数据库中定义。但这并不意味着它们都是同一模型的一部分。可以有多个上下文。在这种情况下,一个用于身份,一个(或更多)用于业务。

现在为什么分开那两个?业务模型和身份模型之间最重要的区别是不能直接调用身份表。我们使用Owin上下文来调用UserManager / RoleManager。

这就是我们无法将这些表添加到业务模型的原因。事情可以以不安全的方式改变。此外,我们不希望企业对授权有任何了解。只要识别并授权用户,就不应该如何做到这一点。

此外,您可能希望实施OpenId和基于声明的授权。在这种情况下,信息不必在数据库中可用。

这个想法是创建身份表AspNetUsers和业务表People的1:1关系。可能存在一些冗余,例如电子邮件或(用户)名称。但这不是一个问题。 People表应包含您要在业务模型中使用的所有信息。业务表应仅与People相关,而不是与AspNetUsers相关。

现在关于AspNetUsers和People之间的链接。有四种选择:

  1. 设置People.Id = AspNetUser.Id。请注意,AspNetUser.Id不一定是GUID。您可以添加自己的值作为键。

  2. 设置AspNetUser.Id = People.Id。

  3. 将列AspNetUserId添加到People。不需要修改身份。您也可以将人员添加到身份模型中,但我不认为您可以在一个事务中创建两个记录。您可以使用User.Identity.GetId()来获取AspNetUser.Id。但是,您可以问自己,企业是否应该了解这些信息。

  4. 将列PeopleId添加到AspNetUsers。您需要扩展IdentityUser才能添加PeopleId。一个优点是您不需要AspNetUser Id,但您可以使用实际的人员ID。使用OpenId或声明时,您可以从声明中获取People.Id,并且您不必将AspNetUser.Id添加到业务中。 (可选)您可以将人员添加到模型中,并将其添加为扩展IdentityUser的导航属性。创建用户时,您可以在一次交易中执行此操作。

  5. 如果您在单独的上下文中创建用户,则您需要自己处理回滚。但在向People添加记录之前,您已经可以测试是否可以添加AspNetUser:具有有效的名称/电子邮件和密码。

    由于您的业务模型与People表相关,因此您可以查询所有资产并使用People表连接以获取其他信息。或者您可以获得当前用户的所有资产。

    是的,有两种情况。身份模型,包含AspNet ...表格+可选人员。和业务模型,其中包含所有ERP表+资产+人员。

    您可以考虑首先将代码用于身份框架2,然后将数据库首先用于业务模型。

    我希望这会有所帮助。如果没有,请继续聊天。

    - 更新 -

    答案集中在领域的分离:身份和业务。这就是为什么我没有讨论关于AspNetUsers表的一个可能的替代方案。

    这两个模型是数据库的表示,这意味着数据库不必完全匹配。您可以随意映射表格和字段,只要它们不会破坏数据库逻辑。

    由于AspNetusers和People具有1:1的关系,并且 这两个表存在于同一个数据库中时,您也可以将这两个表合并到AspNetUsers表中。您还可以向AspNetUsers表添加关系,但您可能需要添加额外的Id(int)列而不是使用当前的Id(字符串)。

    这并不意味着可以丢弃People类,除了我们必须更改表映射:AspNetUsers。

    示例:

    [Table("AspNetUsers")]
    public class People
    {
        [Required]
        [StringLength(128)]
        public string Id { get; set; }
    
        public string FirstName { get; set; }
    
        public string LastName { get; set; }
    }
    

    如您所见,敏感字段未映射。然而,我们需要Id字段。您现在可以读取和更新映射的字段。

    您不必扩展IdentityUser。您可以添加AspNetUser,然后在其他上下文中使用People更新字段。但是,如果要在一个事务中添加用户,可能更容易扩展IdentityUser(确保您在People和ApplicationUser中定义新字段):

    public class ApplicationUser : IdentityUser
    {
        public string FirstName { get; set; }
    
        public string LastName { get; set; }
    }
    

    有许多优点:

    1. 只有一个交易可以添加用户。
    2. 您无法公开敏感字段,因为它们未映射到人员。
    3. 您无法将人员添加到数据库,因为某些必填字段未映射到人员。
    4. 请注意,这可能不适用于所有类型的模型(代码优先/数据库优先+迁移)。

答案 1 :(得分:3)

您想要做的最常见的方法是在ApplicationDbContext中将您的其他模型添加为DbSet。

public class Asset
{
      public string CreatedBy { get; set; }

      public string UserId { get; set; }

      public ApplicationUser User { get; set; }
}

public class ApplicationUser : IdentityUser
{
     public IList<Asset> Assets { get; set; }
}

public class ApplicationDbCotext : IdentityDbContext<ApplicationUser>
{
     public DbSet<Asset> Assets { get; set; }
}

正如我所提到的,这是最常见的方法,因为更新Identity包应该对您的架构没有影响。这就是说你应该在推送到生产之前测试更新。

更新: 请注意,当您使用One to Many关系时,您将在我们的Asset模型中看到User Id外键和User对象的属性。由于这种关系,我们可以在用户中创建List<Asset>以完成“一对多”关系。这将允许我们直接查询属于用户的资产。

至于Code First vs Database首先,差异实际上取决于如何定义实体框架和数据库之间的映射。

正如我在下面提到的那样,如果您将Identity上下文与业务上下文分开,或者您应将它们分成单独的数据库,则没有一个适合所有答案的答案。现实情况是,只有您可以根据自己的需要回答这个问题。将所有数据放在单个数据库中更为常见。也就是说,为了确保有关用户的识别信息(例如他们的姓名,电子邮件和密码哈希)与其地址或支付信息等信息分开,可以说一些事情。权衡的是,您可以发现自己试图维护应该捆绑在一起的对象,但这些对象只是松散相关,因为它们位于不同的数据库中。此外,您还需要确保使用不同的用户/密码连接到不同的数据库,最好将数据库放在不同的服务器上,因为如果服务器受到损害,您无需进行整个练习。获得理论上的安全性的权衡最终变得如此不切实际,因为你必须要做的另一件事是,你最终会在一个数据库中看到所有内容,你可以集中所有的强化工作。

File -> New具有个人身份验证的项目时,通常应该为您创建ApplicationDbContext和ApplicationUser对象。您可以根据需要向用户添加任意​​数量的属性和关系。