我需要完成与权限相关的以下内容:
我有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 A
有User B
作为联系人,但不是User C
的联系人(User B
和User 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)
有人可以解释如何处理这些特权。如果你能把我链接到任何可以帮助我开始运作的文档或文章。谢谢。
答案 0 :(得分:7)
不幸的是,Django的授权系统不允许您为每个对象分配权限,仅限于每个类。在这里,我假设您的每个“文档”都是模型类的实例。
但是,可重用的应用程序可以大大简化此任务。查看适用于对象(或行)级别的django-guardian或other packages。
答案 1 :(得分:5)
一般答案是找到文档所有者与给定联系人之间的距离。在计算机科学术语中,这是directed graph。
有一篇很好的文章,其中包含一些SQL查询,涵盖http://techportal.inviqa.com/2009/09/07/graphs-in-the-database-sql-meets-social-networks/的这个主题。而不是试图总结整篇文章,这里是如何概念化问题:
另外,如果作为“联系人”是相互的,您可以绘制线段(或双向箭头)而不是箭头。在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 B
和User
模型与标准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次。