资源列表授权的最佳实践是什么?

时间:2021-04-19 20:04:11

Publishing and/or collaborative applications often involve the sharing of access to resources. In a portal a user may be granted access to certain content as a member of a group or because of explicit access. The complete set of content could include public content, group membership content, and private user content. Or, with collaborative applications, we may want to pass along resources as part of a workflow or share custody of a document for editing purposes.

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

Since most applications store these resources in a database you typically create queries like 'Get all the documents that I can edit' or 'Get all the content I can see'. Where 'can edit' and 'can see' are the user's privileges.

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

I have two questions:

我有两个问题:

  1. It's quite easy to authorize the user once you've retrieved a resource, but how do you efficiently perform authorization on the list of available resources? And,

    一旦检索到资源,就很容易授权用户,但是如何在可用资源列表上有效地执行授权?和,

  2. Can this kind of authorization be separated from the core of the application? Perhaps into a separate service? Once separated, how could you filter queries like 'Get me all the documents I can see with title like [SomeSearchTerm]'? It seems to me your separate system would have to copy over a lot of reference data.

    这种授权可以与应用程序的核心分开吗?也许进入一个单独的服务?一旦分开,你怎么能过滤这样的查询,比如'让我看到所有我能看到的文件,像[SomeSearchTerm]这样的标题?在我看来,你的独立系统必须复制大量的参考数据。

3 个解决方案

#1


5  

You may be interested in reading this article by Steffen Bartsch. It summarizes all authorization plugins for Ruby on Rails, and I am sure it will help you find your solution (although this article is about Rails plugins, the concepts are easily exportable outside Rails).

您可能有兴趣阅读Steffen Bartsch撰写的这篇文章。它总结了Ruby on Rails的所有授权插件,我相信它可以帮助您找到解决方案(尽管本文是关于Rails插件的,这些概念可以在Rails之外轻松导出)。

Steffen also built his own plugin, called "Declarative Authorization" which seems to match your needs, IMHO:

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

  • on the one hand, you define roles (such as "visitor", "admin"...). Your users are associated to these roles (in a many-to-many relationship). You map these roles to privileges (again in a many-to-many relationship). Each privilege is linked to a given context. For example, the role "visitor" may have privilege "read documents". In this example, "read" is the privilege, and it is applied to the "documents" context.
    • Note: in Steffen's plugin, you can define a hierarchy of roles. For example you might want to have the "global_admin" role include the "document_admin" role, as well as the "comment_admin" role, etc.
    • 注意:在Steffen的插件中,您可以定义角色的层次结构。例如,您可能希望“global_admin”角色包含“document_admin”角色,以及“comment_admin”角色等。

    • You can also defines hierarchies of privileges: for example, the "manage" privilege could include the "read", "update", "add" and "delete" privileges.
    • 您还可以定义权限的层次结构:例如,“管理”权限可以包括“读取”,“更新”,“添加”和“删除”权限。

  • 一方面,您定义角色(例如“访客”,“管理员”......)。您的用户与这些角色相关联(以多对多关系)。您将这些角色映射到特权(再次以多对多关系)。每个权限都链接到给定的上下文。例如,角色“访客”可能具有“阅读文档”的特权。在此示例中,“read”是权限,它应用于“documents”上下文。注意:在Steffen的插件中,您可以定义角色的层次结构。例如,您可能希望有“global_admin”的角色包括“document_admin”的角色,还有“comment_admin”的角色,等你也可以定义的权限等级结构中:例如,“管理”权限也包括了“读“,”更新“,”添加“和”删除“权限。

  • on the other hand, you code your application thinking in terms of privileges and contexts, not in terms of roles. For example, the action to display a document should only check whether the user has the privilege to "read" in the "documents" context (no need to check whether the user has the "visitor" role or any other role). This greatly simplifies your code, since most of the authorization logic is extracted elsewhere (and perhaps even defined by someone else).
  • 另一方面,您根据特权和上下文对应用程序进行编码,而不是根据角色进行编码。例如,显示文档的操作应仅检查用户是否具有在“文档”上下文中“读取”的权限(无需检查用户是否具有“访问者”角色或任何其他角色)。这大大简化了代码,因为大多数授权逻辑都是在其他地方提取的(甚至可能是由其他人定义的)。

This separation between the definition of the user roles and the definition of the application-level privileges guarantees that your code will not change every time you define a new role. For example, here is how simple the access-control would look like in a controller :

用户角色定义与应用程序级特权定义之间的这种分离可确保每次定义新角色时代码都不会更改。例如,以下是访问控制在控制器中的外观简单:

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

And inside a view:

在视图中:

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

Steffen's plugin also allows for object-level (ie. row-level) access-control. For example, you might want to define a role such as "document_author" and give it "manage" privilege on "documents", but only if the user is the author of the document. The declaration of this rule would probably look like this:

Steffen的插件还允许对象级(即行级)访问控制。例如,您可能希望定义一个角色,例如“document_author”,并为“文档”赋予它“管理”权限,但前提是用户是文档的作者。此规则的声明可能如下所示:

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

That's all there is to it! You can now get all the documents that the user is allowed to update like this:

这里的所有都是它的!您现在可以获得允许用户更新的所有文档,如下所示:

Document.with_permissions_to(:update)

Since the "manage" privilege includes the "update" privilege, this will return the list of documents whose author is the current user.

由于“管理”权限包括“更新”权限,因此将返回其作者是当前用户的文档列表。

Of course, not every application will need this level of flexibility... but yours might.

当然,并非每个应用程序都需要这种程度的灵活性......但是你的应用程序可能会。

#2


0  

I generally have a schema like this

我通常有这样的架构

Users −−∈ UserDocuments ∋−− Documents

用户 - ∈UserDocuments∋--文件

Then I create a view "ProfiledDocuments"

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

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

Then run the search queries on ProfiledDocuments always using a UserId filter. With appropriate indexes it works well enough.

然后始终使用UserId过滤器在ProfiledDocuments上运行搜索查询。使用适当的索引,它运作良好。

If you need more complex permissions, you can do it with an extra field in the UserDocuments many to many table which specifies the kind of permission.

如果您需要更复杂的权限,可以使用UserDocuments中的多个字段来执行此操作,该字段指定了权限类型。

#3


0  

Though your question is quite elaborated, there is actually some missing context.
What defines the documents a user has privileges for? Can a user only edit his "own" files? Is there a role-based mechanism here? Is it more MAC-oriented (i.e. a user can see a level of security)? Is there a defining attribute to the data (e.g. department)?

虽然你的问题很详细,但实际上有一些缺失的背景。什么定义了用户拥有权限的文档?用户只能编辑他自己的“自己的”文件吗?这里有基于角色的机制吗?它是否更加面向MAC(即用户可以看到安全级别)?是否有数据的定义属性(例如部门)?

All these questions together may give a better picture, and allow a more specific answer.

所有这些问题可以共同提供更好的图片,并提供更具体的答案。

If documents are "owned" by a specific user, its pretty straightforward - have an "owner" field for the document. Then, query for all documents owned by the user.
Similarly, if you can pre-define the list of named users (or roles) that have access, you can query for a joined list between the documents, the list of authorized users/roles, and the user (or his roles).
If a user gets permissions according to his department (or other similar document's attribute), you can query on that.
Similarly, you can query for all documents with a level of security equal or lower to that of the user's privileges. If this is dynamic workflow, each document should typically be marked with its current state, and/or next expected step; which users can perform that next step is simply another privilege/role (treat the same as above).
Then, of course, you'll want to do a UNION ALL between all those and public documents...

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

Btw, if I have not made it clear, this is not a simple issue - do yourself a favor and find pre-built infrastructure to do it for you. Even at the cost of simplifying your authorization schemata.

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

#1


5  

You may be interested in reading this article by Steffen Bartsch. It summarizes all authorization plugins for Ruby on Rails, and I am sure it will help you find your solution (although this article is about Rails plugins, the concepts are easily exportable outside Rails).

您可能有兴趣阅读Steffen Bartsch撰写的这篇文章。它总结了Ruby on Rails的所有授权插件,我相信它可以帮助您找到解决方案(尽管本文是关于Rails插件的,这些概念可以在Rails之外轻松导出)。

Steffen also built his own plugin, called "Declarative Authorization" which seems to match your needs, IMHO:

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

  • on the one hand, you define roles (such as "visitor", "admin"...). Your users are associated to these roles (in a many-to-many relationship). You map these roles to privileges (again in a many-to-many relationship). Each privilege is linked to a given context. For example, the role "visitor" may have privilege "read documents". In this example, "read" is the privilege, and it is applied to the "documents" context.
    • Note: in Steffen's plugin, you can define a hierarchy of roles. For example you might want to have the "global_admin" role include the "document_admin" role, as well as the "comment_admin" role, etc.
    • 注意:在Steffen的插件中,您可以定义角色的层次结构。例如,您可能希望“global_admin”角色包含“document_admin”角色,以及“comment_admin”角色等。

    • You can also defines hierarchies of privileges: for example, the "manage" privilege could include the "read", "update", "add" and "delete" privileges.
    • 您还可以定义权限的层次结构:例如,“管理”权限可以包括“读取”,“更新”,“添加”和“删除”权限。

  • 一方面,您定义角色(例如“访客”,“管理员”......)。您的用户与这些角色相关联(以多对多关系)。您将这些角色映射到特权(再次以多对多关系)。每个权限都链接到给定的上下文。例如,角色“访客”可能具有“阅读文档”的特权。在此示例中,“read”是权限,它应用于“documents”上下文。注意:在Steffen的插件中,您可以定义角色的层次结构。例如,您可能希望有“global_admin”的角色包括“document_admin”的角色,还有“comment_admin”的角色,等你也可以定义的权限等级结构中:例如,“管理”权限也包括了“读“,”更新“,”添加“和”删除“权限。

  • on the other hand, you code your application thinking in terms of privileges and contexts, not in terms of roles. For example, the action to display a document should only check whether the user has the privilege to "read" in the "documents" context (no need to check whether the user has the "visitor" role or any other role). This greatly simplifies your code, since most of the authorization logic is extracted elsewhere (and perhaps even defined by someone else).
  • 另一方面,您根据特权和上下文对应用程序进行编码,而不是根据角色进行编码。例如,显示文档的操作应仅检查用户是否具有在“文档”上下文中“读取”的权限(无需检查用户是否具有“访问者”角色或任何其他角色)。这大大简化了代码,因为大多数授权逻辑都是在其他地方提取的(甚至可能是由其他人定义的)。

This separation between the definition of the user roles and the definition of the application-level privileges guarantees that your code will not change every time you define a new role. For example, here is how simple the access-control would look like in a controller :

用户角色定义与应用程序级特权定义之间的这种分离可确保每次定义新角色时代码都不会更改。例如,以下是访问控制在控制器中的外观简单:

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

And inside a view:

在视图中:

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

Steffen's plugin also allows for object-level (ie. row-level) access-control. For example, you might want to define a role such as "document_author" and give it "manage" privilege on "documents", but only if the user is the author of the document. The declaration of this rule would probably look like this:

Steffen的插件还允许对象级(即行级)访问控制。例如,您可能希望定义一个角色,例如“document_author”,并为“文档”赋予它“管理”权限,但前提是用户是文档的作者。此规则的声明可能如下所示:

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

That's all there is to it! You can now get all the documents that the user is allowed to update like this:

这里的所有都是它的!您现在可以获得允许用户更新的所有文档,如下所示:

Document.with_permissions_to(:update)

Since the "manage" privilege includes the "update" privilege, this will return the list of documents whose author is the current user.

由于“管理”权限包括“更新”权限,因此将返回其作者是当前用户的文档列表。

Of course, not every application will need this level of flexibility... but yours might.

当然,并非每个应用程序都需要这种程度的灵活性......但是你的应用程序可能会。

#2


0  

I generally have a schema like this

我通常有这样的架构

Users −−∈ UserDocuments ∋−− Documents

用户 - ∈UserDocuments∋--文件

Then I create a view "ProfiledDocuments"

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

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

Then run the search queries on ProfiledDocuments always using a UserId filter. With appropriate indexes it works well enough.

然后始终使用UserId过滤器在ProfiledDocuments上运行搜索查询。使用适当的索引,它运作良好。

If you need more complex permissions, you can do it with an extra field in the UserDocuments many to many table which specifies the kind of permission.

如果您需要更复杂的权限,可以使用UserDocuments中的多个字段来执行此操作,该字段指定了权限类型。

#3


0  

Though your question is quite elaborated, there is actually some missing context.
What defines the documents a user has privileges for? Can a user only edit his "own" files? Is there a role-based mechanism here? Is it more MAC-oriented (i.e. a user can see a level of security)? Is there a defining attribute to the data (e.g. department)?

虽然你的问题很详细,但实际上有一些缺失的背景。什么定义了用户拥有权限的文档?用户只能编辑他自己的“自己的”文件吗?这里有基于角色的机制吗?它是否更加面向MAC(即用户可以看到安全级别)?是否有数据的定义属性(例如部门)?

All these questions together may give a better picture, and allow a more specific answer.

所有这些问题可以共同提供更好的图片,并提供更具体的答案。

If documents are "owned" by a specific user, its pretty straightforward - have an "owner" field for the document. Then, query for all documents owned by the user.
Similarly, if you can pre-define the list of named users (or roles) that have access, you can query for a joined list between the documents, the list of authorized users/roles, and the user (or his roles).
If a user gets permissions according to his department (or other similar document's attribute), you can query on that.
Similarly, you can query for all documents with a level of security equal or lower to that of the user's privileges. If this is dynamic workflow, each document should typically be marked with its current state, and/or next expected step; which users can perform that next step is simply another privilege/role (treat the same as above).
Then, of course, you'll want to do a UNION ALL between all those and public documents...

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

Btw, if I have not made it clear, this is not a simple issue - do yourself a favor and find pre-built infrastructure to do it for you. Even at the cost of simplifying your authorization schemata.

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