【发布时间】:2009-09-23 16:44:07
【问题描述】:
我正在尝试为 Django 模型实施基于行的安全检查。这个想法是,当我访问模型管理器时,我会指定一些用于数据库查询的附加信息,以便只从数据库中获取允许的实例。
例如,我们可以有两个模型:用户和项目。每个项目都属于某个用户,并且用户可能连接到许多项目。并设置一些限制,根据这些限制,用户可能会看到或可能不会看到另一个用户的项目。我想将此限制与其他查询元素分开并编写如下内容:
items = Item.scoped.forceRule('user1').all() # all items visible for 'user1'
或
# show all items of 'user2' visible by 'user1'
items = Item.scoped.forceRule('user1').filter(author__username__exact = 'user2')
为了实现这一点,我做了以下几点:
class SecurityManager(models.Manager):
def forceRule(self, onBehalf) :
modelSecurityScope = getattr(self.model, 'securityScope', None)
if modelSecurityScope :
return super(SecurityManager, self).get_query_set().filter(self.model.securityScope(onBehalf))
else :
return super(SecurityManager, self).get_query_set()
def get_query_set(self) :
#
# I need to know that 'onBehalf' parameter here
#
return super(SecurityManager, self).get_query_set()
class User(models.Model) :
username = models.CharField(max_length=32, unique=True)
class Item(models.Model) :
author = models.ForeignKey(User)
private = models.BooleanField()
name = models.CharField(max_length=32)
scoped = SecurityManager()
@staticmethod
def securityScope(onBehalf) :
return Q(author__username__exact = onBehalf) | Q(bookmark__private__exact = False)
对于显示的示例,它可以正常工作,但在以下情况下会死:
items = Item.scoped.forceRule('user1').filter(author__username__exact = 'user2') # (*)
items2 = items[0].author.item_set.all() # (**)
当然,items2 由“user2”的所有项目填充,而不仅仅是符合规则的项目。这是因为当 all() 被执行时,SecurityManager.get_query_set() 没有关于限制集的信息。虽然可以。例如,在 forceRule() 中,我可以为每个实例添加一个字段,然后,如果我可以从管理器访问该字段,则应用所需的规则。
所以,问题是 - 有没有办法将声明 (*) 中提供给 forceRule() 的参数传递给经理,在声明 (**) 中调用。
或者另一个问题 - 我是否在做一些我根本不应该做的奇怪事情?
谢谢。
【问题讨论】:
-
我也面临同样的用例,我想知道你是如何解决这个问题的?谢谢!
标签: python django django-models