社交网站授权

时间:2011-06-13 09:18:36

标签: python django authorization social-networking

我需要完成与权限相关的以下内容:

我有3个用户:

- User A
- User B
- User C

每个用户都有以下文档及相关的访问设置:

- User A
    - Document A1, only allow contacts to view
    - Document A2, allow everyone to view
    - Document A3, allow no one to view except myself
    - Document A4, allow contacts, and contacts of contacts to view
- User B
    - Documents B1, B2, B3, B4 with similar privileges
- User C
    - Documents C1, C2, C3, C4 with similar privileges

User AUser B作为联系人,但不是User C的联系人(User BUser C是联系人)。

因此,User A将能够查看以下内容:

- Document B1 (contacts can view)
- Document B2 (everyone can view) 
- Document B4 (contacts of contacts)
- Document C2 (everyone can view)
- Document C4 (contacts of contacts)

有人可以解释如何处理这些特权。如果你能把我链接到任何可以帮助我开始运作的文档或文章。谢谢。

5 个答案:

答案 0 :(得分:7)

不幸的是,Django的授权系统不允许您为每个对象分配权限,仅限于每个类。在这里,我假设您的每个“文档”都是模型类的实例。

但是,可重用的应用程序可以大大简化此任务。查看适用于对象(或行)级别的django-guardianother packages

答案 1 :(得分:5)

一般答案是找到文档所有者与给定联系人之间的距离。在计算机科学术语中,这是directed graph

有一篇很好的文章,其中包含一些SQL查询,涵盖http://techportal.inviqa.com/2009/09/07/graphs-in-the-database-sql-meets-social-networks/的这个主题。而不是试图总结整篇文章,这里是如何概念化问题:

  • 从一张白纸开始。
  • 在页面的某个位置为每个人绘制一个点(在本例中为用户A,B和C)。在CS术语中,这是一个“节点”。
  • 从用户绘制箭头到他们的所有联系人。在CS术语中,这是“有向边缘”或“弧形”。
    • 这个问题并不明确,但看起来用户C必须是用户B的联系人,或联系用户A其他联系人的另一个联系人(因为用户A可以阅读C2和C4)。
    • 因此,在这种情况下,您将从用户A - >中抽取用户B和用户B - >用户C。

另外,如果作为“联系人”是相互的,您可以绘制线段(或双向箭头)而不是箭头。在CS术语中,这将是“无向”与“有向”图形。 Facebook关系是一种无关的关系;如果有人是我的朋友,那么我也是他们的朋友。相比之下,如果有人在我的Outlook通讯录中,我不一定是他们的。所以这是一种有针对性的关系。

随着更多用户被添加到绘图中,您会注意到用户的联系人距离一步之遥,他们的联系人联系人距离两步之遥。但是你只能沿着箭头的方向行进。

因此,联系人的问题是,“我如何找到图表距离为1的所有节点?”接触联系人的问题是,“我如何找到图形距离为2的所有节点?”。虽然“两个或更少”可能更合适,因为您希望直接联系人可以访问所有“联系人联系人”内容。

对于一般情况,本文中描述的一些SQL查询可能提供一些见解。但是根据您的具体需要,我会考虑使用一些连接。

让我们考虑一个Users表,主键id及其他字段,以及HasContact表,其中只有两列:userId和{{1 }}。我们假设用户A的id为1,用户B为2,用户C为3. HasContact有行(1,2)和(2,3)来表示上述关系。

一组非常简单的SQL连接可以生成所有朋友或所有朋友朋友的列表。

以下查询将返回用户联系人的所有ID:

contactId

如果您知道用户ID,授权查询可能非常简单:

SELECT contact.id
  FROM Users "user"
    LEFT JOIN Relationships "rel"
      ON user.id = rel.userid
    LEFT JOIN Users "contact"
      ON rel.contactId = contact.id
  WHERE user.id = $id_of_current_user

如果查询返回0,那么我们就知道当前用户是文档所有者的联系人之一。

我们可以更新第二个查询以指示用户是否是联系人:

SELECT count(*)
  FROM Relationships "rel"
  WHERE rel.userid = $document_owner_user_id
    AND rel.contactid = $id_of_current_user

只要“关系”表中有条目,SELECT count(*) FROM Relationships "rel_1" INNER JOIN Relationships "rel_2" ON rel_1.contactId = rel_2.userId WHERE rel_1.userid = $document_owner_user_id AND rel_2.contactid = $id_of_current_user ($document_owner_user_id, X)都存在,就应该返回非零值。否则,它将返回零。

我知道这是一个长期而且有点间接的答案,所以如果您有任何问题请发表评论。

答案 2 :(得分:3)

你基本上需要的是Limit access to logged-in users that pass a test。但是具有“联系人联系人”的部分可能导致非常复杂的sql查询。我建议你重新考虑这个要求。 (我有很多我喜欢和信任的好朋友。但他们有各种各样奇怪的人作为朋友......)

答案 3 :(得分:3)

您需要的是access control list(ACL),它将根据每个用户网络进行更改。 ACL和基于对象的权限在标准django.contrib.auth模块中不可用。我实际上已经在Django中实现了一个ACL,但它基于类不是基于对象的。在您的应用程序的上下文中,只要他在某个授权组(比如User A组),它就像Admins一样可以查看任何人的文档。但是,User A可以查看User B个文档,如果User A位于Contacts的{​​{1}}组中,则可以使其工作。

我可以解释一下自定义身份验证应用程序的模型结构。 User BUser模型与标准Django auth app相同(您可以从models.py复制)。然后,您需要一个模型来表示不同级别的权限(Everyone,ContactsOfContact,Contact,Myself)。这样做很简单,因为在标准django auth组模型中添加了另一个字段。此字段将是同一模型的外键,它将表示每个组将继承的组。现在模型看起来像这样,

Permission

现在,您可以添加class SocialGroup(models.Model): name = models.CharField(unique=True, max_length=150) parent = models.ForeignKey('self') 组之类的关系,可以通过将Contacts组设置为Everyone组的父级来查看Everyone组可以查看的所有内容。请注意,Contacts模型没有外键关系。接下来,我们需要一种方法来指定用户和组之间的关系。

Permission

使用此模型,我们可以说class Relationship(models.Model): user = models.ForeignKey(User) related_user = models.ForeignKey(User) related_by = models.ForeignKey(SocialGroup) (related_user)与User A User B(related_by)组中的User B(用户)相关。然后我们需要一种方法来为每个文档指定权限。

Contacts

现在我们可以说class DocumentPermissions(models.Model): document = models.ForeignKey(Document) group = models.ForeignKey(SocialGroup) Permission = models.ForeignKey(Permission) 群组Contacts拥有can_view权限。请注意,此模型应该转到Document模型所在的位置,而不是在我们新的auth应用程序中auth models.py.就是这样,现在我们所要做的就是编写逻辑以查找给定文档的给定用户的权限。因此,当Document B1尝试查看User B

时,我们需要执行此操作
  • 首先检查文档属于哪个人(Document A1
  • 然后找到所有者与尝试从关系模型(联系人)访问文档的人之间的关系组。
  • 然后检查User A以查看该组或其继承的任何组是否有权查看该文档。

这个逻辑可以在Django的新认证后端(将使用我们的新auth模型)中实现,它可以进入新的auth应用程序。您可以在标准Django model backend中查看DocumentPermissions功能。这就是你需要做的。所有装饰者和东西仍然有用。

答案 4 :(得分:0)

您可以加入“朋友的朋友”字段。这将是一个非常大的桌子(例如,200 * 200 * N = 40,000 * N ......或者如果你对朋友没有限制,真的很大,有人是一百万人的朋友 - 那是100万人,有100万FoF )但是每个视图比数据库更容易200次。