Próbuję zaimplementować sprawdzanie bezpieczeństwa w wierszach dla modeli Django. Chodzi o to, że kiedy mam dostęp do menedżera modelu, określam dodatkowe informacje, które są używane w zapytaniach do bazy danych, tak że tylko dozwolone są instancje pobierane z bazy danych.Modele Django - przekazywanie dodatkowych informacji do menedżera
Na przykład możemy mieć dwa modele: Użytkownicy i, powiedzmy, Przedmioty. Każda pozycja należy do niektórych Użytkowników, a Użytkownik może być połączony z wieloma Przedmiotami. I niech będą pewne ograniczenia, zgodnie z którymi użytkownik może zobaczyć lub może nie widzieć Przedmiotów innego Użytkownika. Chcę oddzielić to ograniczenia z innymi elementami zapytań i napisać coś takiego:
items = Item.scoped.forceRule('user1').all() # all items visible for 'user1'
lub
# show all items of 'user2' visible by 'user1'
items = Item.scoped.forceRule('user1').filter(author__username__exact = 'user2')
Aby to acheive ułożyć poniższe:
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)
Na pokazanych przykładach działa dobrze , ale umiera na następujące:
items = Item.scoped.forceRule('user1').filter(author__username__exact = 'user2') # (*)
items2 = items[0].author.item_set.all() # (**)
Oczywiście, items2
jest zapełniane przez wszystkie elementy "użytkownika 2", nie tylko te, które są zgodne z regułą. Dzieje się tak, ponieważ po wykonaniu wszystkich() SecurityManager.get_query_set()
nie ma informacji o zestawie ograniczeń. Chociaż mogło. Na przykład w forceRule() mogę dodać pole dla każdej instancji, a następnie, jeśli mogę uzyskać dostęp do tego pola od menedżera, zastosuj wymaganą regułę.
Pytanie brzmi - czy istnieje sposób przekazania argumentu dostarczonego do forceRule()
w komunikacie (*)
do menedżera, wywołanego w oświadczeniu (**)
.
Lub inne pytanie - czy robię dziwne rzeczy, których nie powinienem robić w ogóle?
Dziękuję.
Mam do czynienia z tym samym przypadkiem użycia, zastanawiam się, jak udało się to obejść? dzięki! – ultrajohn