【问题标题】:What are the best-practices around resource list authorization?资源列表授权的最佳实践是什么?
【发布时间】:2008-10-04 16:22:32
【问题描述】:

发布和/或协作应用程序通常涉及共享资源访问权限。在门户中,用户可能被授予对某些内容的访问权限作为组的成员或由于明确的访问权限。完整的内容集可以包括公共内容、群组成员内容和私人用户内容。或者,对于协作应用程序,我们可能希望将资源作为工作流程的一部分传递或共享文档的保管以进行编辑。

由于大多数应用程序将这些资源存储在数据库中,您通常会创建查询,例如“获取我可以编辑的所有文档”或“获取我可以看到的所有内容”。其中“可以编辑”和“可以查看”是用户的权限。

我有两个问题:

  1. 一旦您检索到资源,就很容易授权用户,但是您如何有效地对可用资源列表执行授权呢?还有,

  2. 这种授权可以脱离应用的核心吗?也许进入一个单独的服务?分离后,您如何过滤诸如“获取所有我可以看到的标题为 [SomeSearchTerm] 的文档”之类的查询?在我看来,您的单独系统将不得不复制大量参考数据。

【问题讨论】:

    标签: security authorization


    【解决方案1】:

    您可能有兴趣阅读this article by Steffen Bartsch。它总结了 Ruby on Rails 的所有授权插件,我相信它会帮助您找到解决方案(虽然本文是关于 Rails 插件的,但这些概念很容易在 Rails 之外导出)。

    Steffen 还构建了自己的插件,称为“声明式授权”,它似乎符合您的需求,恕我直言:

    • 一方面,您定义角色(例如“访问者”、“管理员”...)。您的用户与这些角色相关联(以多对多关系)。您将这些角色映射到权限(同样是多对多关系)。每个权限都链接到给定的上下文。例如,角色“visitor”可能具有“阅读文档”权限。在此示例中,“read”是权限,它应用于“documents”上下文。
      • 注意:在 Steffen 的插件中,您可以定义角色层次结构。例如,您可能希望“global_admin”角色包括“document_admin”角色以及“comment_admin”角色等.
      • 您还可以定义权限层次结构:例如,“manage”权限可以包括“read”、“update” 、“添加”和“删除”权限。
    • 另一方面,您根据权限上下文而不是角色来编写应用程序。例如,显示文档的动作应该只检查用户是否有权限在“documents”上下文中“read”(不需要检查用户是否具有“visitor”角色或任何其他角色)。这大大简化了您的代码,因为大部分授权逻辑都在其他地方提取(甚至可能由其他人定义)。

    用户角色的定义和应用程序级权限的定义之间的这种分离保证了您的代码不会在每次定义新角色时发生变化。例如,下面是控制器中访问控制的简单程度:

    class DocumentController [...]
      filter_access_to :display, :require => :read
      def display
        ...
      end
    end
    

    在视图内部:

    <html> [...]
      <% permitted_to?(:create, :documents) do %>
      <%= link_to 'New', new_document_path %>
      <% end %>
    </html>
    

    Steffen 的插件还允许对象级(即行级)访问控制。例如,您可能想要定义诸如“document_author”之类的角色,并赋予它“documents”的“manage”权限,但 strong>仅当用户是文档的作者时。该规则的声明可能如下所示:

    role :document_author do
      has_permission.on :documents do
        to :manage
        if_attribute :author => is {user}
      end
    end
    

    这就是它的全部内容!您现在可以像这样获取允许用户更新的所有文档:

    Document.with_permissions_to(:update)
    

    由于“manage”权限包含“update”权限,这将返回作者为当前用户的文档列表。

    当然,不是每个应用程序都需要这种级别的灵活性......但您可能需要。

    【讨论】:

      【解决方案2】:

      我通常有这样的架构

      Users −−∈ UserDocuments ∋−− Documents

      然后我创建一个视图“ProfiledDocuments”

      SELECT <fields> 
      FROM Documents d 
      INNER JOIN UserDocuments ud on ud.DocumentId = d.Id 
      INNER JOIN Users u ON u.Id = ud.UserId
      

      然后始终使用 UserId 过滤器在 ProfiledDocuments 上运行搜索查询。有了适当的索引,它就可以很好地工作了。

      如果您需要更复杂的权限,您可以使用 UserDocuments 多对多表中的一个额外字段来指定权限类型。

      【讨论】:

        【解决方案3】:

        虽然您的问题非常详尽,但实际上缺少一些上下文。
        什么定义了用户有权访问的文档?用户只能编辑他的“自己的”文件吗?这里有基于角色的机制吗?它是否更面向 MAC(即用户可以看到一定程度的安全性)?数据是否有定义属性(例如部门)?

        所有这些问题加在一起可能会提供更好的画面,并提供更具体的答案。

        如果文档由特定用户“拥有”,则非常简单 - 为文档设置一个“所有者”字段。然后,查询用户拥有的所有文档。
        同样,如果您可以预先定义具有访问权限的命名用户(或角色)列表,您可以查询文档、授权用户/角色列表和用户(或他的角色)之间的连接列表。 如果用户根据其部门(或其他类似文档的属性)获得权限,您可以对其进行查询。
        同样,您可以查询安全级别等于或低于用户权限的所有文档。 如果这是动态工作流程,则每个文档通常都应标有其当前状态和/或下一个预期步骤;哪些用户可以执行下一步只是另一个特权/角色(与上述相同)。
        然后,当然,你会想要在所有这些和公共文件之间做一个 UNION ALL ......

        顺便说一句,如果我没有说清楚,这不是一个简单的问题 - 帮自己一个忙,并找到预先构建的基础设施来为您做这件事。即使以简化您的授权模式为代价。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-01-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-08-06
          • 1970-01-01
          • 2013-09-25
          • 1970-01-01
          相关资源
          最近更新 更多