【问题标题】:Should an object test if a user can edit it, or should a controller do a lookup? MVC4对象应该测试用户是否可以编辑它,还是应该由控制器进行查找? MVC4
【发布时间】:2013-04-22 13:57:32
【问题描述】:

我的数据库如下所示:

[表]用户配置文件

  • 用户名

[表格]类别

  • 类别 ID (PK)
  • 用户名(链接到 UserProfile - 这是记录所有者)
  • ProductID(FK 到 Product Table 相关记录)

[表格]产品

  • 产品 ID (PK)
  • CategoryId(导航属性)

登录的用户只能编辑他们拥有的类别和产品。我很高兴根据控制器从视图中收到的 User.Identity.Name 和 CategoryID 来查找 Category,如果我没有得到记录,那么它不存在或用户不拥有它。我开始认为这不是最好的方法,但它确实有效......

我的问题与处理此类产品检查的最佳方式有关?

  1. 我是否应该有一个使用 ProductId 导航属性的查询,然后获取 UserName 值?
  2. 这应该通过控制器中的 linq 查询还是 Products 类上的方法来完成?即prod.ConfirmOwnerIs(User.Identity.Name)
  3. 这应该是像Helpers.ConfirmUserCanEditObject(prod, User.Identity.Name) 这样的外部辅助方法吗?

这个例子稍微简化了,我的真实数据模型有好几层。这对我来说是一个学习项目,所以我试图避免做一些不必要或以低效方式影响数据库的事情,或者成为维护和测试的野兽。我希望在这里得到一些指导和智慧。谢谢。

【问题讨论】:

    标签: asp.net-mvc-4 user-permissions


    【解决方案1】:

    这种类型的检查是一个横切关注点,我认为在 ActionFilter 中实现会更好。

    【讨论】:

    • 能否针对层次结构不同深度的不同实体使用单个 ActionFilter 来完成?意思是我可以概括实现还是需要为每个实体使用不同的 ActionFilterAttribute?我同意它是跨领域的,我只是无法想象如何干净地实现它。
    • 可以概括一下。你可以实现一个像IOwnable 这样的接口,它在你的模型上公开一个Owner 属性。然后,对于操作过滤器,您可以为目标操作参数的名称设置一个命名属性,以检查其所有权。或者,您可以指定应该检查的目标操作参数的类型,或者如果参数实现IOwnable,甚至只检查所有参数
    • 那么'Owner'属性是否实际上包含数据库中的'OwnerId',或者它是否有逻辑从父记录中找到'OwnerId'?如果每个模型实体都有一个“OwnerId”字段会很容易,但这感觉不对。域模型在这里应该是什么样子?
    【解决方案2】:

    如果您需要良好的安全性,我会让对象和控制器都这样做 - 对象只是抛出一个致命异常,而控制器应该确保用户界面永远不会让用户陷入以下情况会抛出异常。

    基本上,好的安全性需要简单,应该是两个语句“我们有xxx权限吗?”还有“现在就死”。

    由于这对用户不够友好,您还可以将复杂的控制器代码放入其中以很好地处理事情,但这不应被视为您的安全系统的一部分。

    【讨论】:

    • 所以我在这里读到的是,应该真正询问对象是否可以修改特定用户并且控制器会相应地采取行动,这是你的意思吗?换句话说,对象实现安全性,控制器使用该实现。如果是这样,每个对象是否会沿着树向上查找根并检查谁拥有根记录?您会为每个对象实现该查询还是实现一种方法来检查一个级别并递归调用它(在每个父对象上,直到您位于顶部)?
    • 不,这不是我的意思。您应该有一个与您的代码的其余部分完全分离的身份验证系统,并且应该可以通过一条语句询问当前登录的用户是否可以执行特定的操作(例如查看id 为 42 的“foo”类型的对象)。您的对象应该这样做,如果它返回 false,则抛出异常,您的控制器应该这样做,但会反弹到登录表单。您的身份验证代码不应该知道其余代码是如何工作的,您的其余代码也不应该知道身份验证是如何工作的。这将减少错误/安全漏洞。
    • 听起来您正在尝试做一些非常复杂的事情。不要那样做,复杂性会导致错误,并且您无法承受涉及安全性的错误。找到一种更简单的方法来解决问题。例如,如果允许用户“bob”查看 id 为“42”的照片,那么在某处应该有一条记录,例如 {user: bob, type: view-photo, id: 42}。如果该记录存​​在,则 bob 可以查看照片。
    • 另外,不要忘记进行一些单元测试以确保抛出这些异常。测试控制器是否总是让用户跳转到登录表单并不重要,也更难测试,但只要对象抛出异常,你就知道一切都是安全的。
    • 感谢您的澄清,如果我能提供帮助,我实际上是在尝试不做一些复杂的事情,所以我感谢您的 cmets。我的应用程序中只有两个级别的访问权限,完全或无 - 而且它仅基于所有权。我不确定添加完整的访问控制系统是否会为我简化事情......我只需要一种简单的方法来确定登录用户是否拥有记录,但它可能是 4 或 5 个关系深度包含“OwnerId”字段的根记录。在我的所有模型实体上都有一个“OwnerId”字段是不是很糟糕?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-11
    • 2018-04-27
    • 2018-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多