如何解决社交网站中的授权
| 我需要完成以下与特权相关的操作: 我有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)
有人可以解释一下如何处理这些特权。并且,如果您可以将我链接到任何文档或文章,这些文档或文章将帮助我快速开展工作。谢谢。
解决方法
通常的答案是找到文档所有者与给定联系人之间的距离。用计算机科学的术语来说,这是有向图。
在http://techportal.inviqa.com/2009/09/07/graphs-in-the-database-sql-meets-social-networks/上有一篇不错的文章,其中包含一些SQL查询。而不是尝试总结整个文章,这里是如何概念化问题的方法:
从一张空白纸开始。
在每个人的页面上的某个地方画一个点(在这种情况下,是用户A,B和C)。用CS术语来说,这是一个“节点”。
向用户绘制一个指向所有联系人的箭头。用CS术语来说,这是\“定向边\”或\“弧\”。
这在问题中不是很明确,但是看起来用户C必须是用户B的联系人,或者是用户A的其他联系人的另一个联系人(因为用户A可以读取C2和C4)。
因此,在这种情况下,您将从用户A->用户B,以及用户B->用户C中绘制。
顺便说一句,如果一个\“ contact \”是相互的,则可以绘制线段(或双向箭头)而不是箭头。用CS术语来说,这将是“无向”图与“有向”图。 Facebook关系是一种无方向的关系;如果有人是我的朋友,那么我也是他们的朋友。相比之下,如果有人在我的Outlook通讯簿中,则我不一定在他们的通讯簿中。因此,这是直接关系。
随着更多用户添加到图形中,您会注意到用户的联系人距离只有一步之遥,而他们的联系人距离也只有两步之遥。但是您只能沿箭头方向行驶。
因此,联系人的问题是“如何查找图形距离为1的所有节点?”联系人的问题是“如何查找图形距离为2的所有节点?” 。尽管“两个或两个以下”可能更合适,但是您希望直接联系人可以访问所有“联系人”内容。
对于一般情况,文章中描述了一些SQL查询,这些查询可能会提供一些见解。但是对于您的特定需求,我会考虑仅使用一些联接。
让我们考虑一个带有主键“ 10”及其其他字段的“ 9”表和一个只有两列的“ 11”表:“ 12”和“ 13”。我们假设用户A的ID为1,用户B为2,用户C为3。HasContact的行(1、2)和(2、3)代表了上述关系。
一组非常简单的SQL连接可以生成所有朋友或所有朋友的列表。
以下查询将返回用户联系人的所有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
如果您知道用户标识,那么授权查询可能非常简单:
SELECT count(*)
FROM Relationships \"rel\"
WHERE rel.userid = $document_owner_user_id
AND rel.contactid = $id_of_current_user
如果查询返回0,则说明当前用户不是文档所有者的联系人之一。
我们可以更新第二个查询,以指示用户是否为联系人:
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
只要关系表中存在条目ѭ17entries和(X,$id_of_current_user)
都存在,就应该返回非零值。否则,它将返回零。
我知道这是一个漫长而间接的答案,因此,如果您有任何疑问,请发表评论。
, 不幸的是,Django的授权系统不允许您为每个对象(每个类)分配权限。在这里,我假设您的每个\“ Document \”都是模型类的实例。
但是,有些可重用的应用程序可以大大简化此任务。查看django-guardian或其他在对象(或行)级别工作的软件包。
, 您基本上需要的是将访问权限限制为通过测试的登录用户。但是带有“ contacts of contacts”的部分会导致非常复杂的sql查询。我建议您重新考虑该要求。 (我有很多我喜欢和信任的好朋友。但是他们有各种各样的怪人作为朋友...)
,您需要的是一个访问控制列表(ACL),它将根据每个用户网络而变化。 ACL和基于对象的权限在标准ѭ19模块中不可用。我实际上已经在Django中实现了ACL,但是它是基于类而不是基于对象的。在您的应用程序上下文中,User A
可以查看任何人的文档,只要他在某个授权组(例如Admins
组)中即可。但是,如果User A
属于Contacts
组中的User B
,那么User A
就可以查看User B
的文档。
我可以根据定制的身份验证应用程序的模型结构来说明如何做到这一点。 User
和Permission
模型将与标准Django auth应用相同(您可以从models.py复制它)。然后,您需要一个模型来表示不同级别的权限(每个人,ContactsOfContact,Contact和Myself)。这样做很简单,只需向标准django身份验证组模型添加另一个字段即可。该字段将是同一模型的外键,它将代表每个组将从其继承的组。现在模型看起来像这样,
class SocialGroup(models.Model):
name = models.CharField(unique=True,max_length=150)
parent = models.ForeignKey(\'self\')
现在,您可以通过将Everyone
组设置为Contacts
组的父级来添加诸如Contacts
组可以查看Everyone
组可以查看的所有内容的关系。请注意,with28ѭ模型没有外键关系。接下来,我们需要一种方法来指定用户和组之间的关系。
class Relationship(models.Model):
user = models.ForeignKey(User)
related_user = models.ForeignKey(User)
related_by = models.ForeignKey(SocialGroup)
通过这个模型,我们可以说User A
(related_user)与User B
(user)相关,因为它在User B
的Contacts
(related_by)组中。然后,我们需要一种为每个文档指定权限的方法。
class DocumentPermissions(models.Model):
document = models.ForeignKey(Document)
group = models.ForeignKey(SocialGroup)
Permission = models.ForeignKey(Permission)
现在我们可以说Contacts
组对Document B1
具有can_view
权限。请注意,此模型应转到文档模型所处的任何位置,而不要在我们新的身份验证应用程序中对auth models.py进行身份验证。就是这样,现在我们要做的就是编写逻辑,以查找给定文档的给定用户的权限。所以这是当User B
尝试查看Document A1
时我们需要做的,
首先检查文件所属的人(User A
)
然后在所有者和尝试从关系模型(联系人)访问文档的所有者之间找到关系组。
然后检查“ 47”以查看该组或从其继承的任何组是否具有查看文档的权限。
可以在Django的新身份验证后端(将使用我们的新auth模型)中实现此逻辑,该后端可以进入新的auth应用。您可以在标准Django模型后端中检查“ 48”功能。这就是您需要做的。所有的装饰器和东西仍然可以使用。
, 您可以包含“朋友的朋友”字段。这将是一个非常大的表(例如200 * 200 * N = 40,000 * N ...或如果您对朋友没有限制的话,那将会是巨大的,某人是一百万人的朋友-那就是一百万人, 1百万FoF),但比每次访问数据库200次更容易。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。