2009-09-23 3 views
8

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ę.

+0

Mam do czynienia z tym samym przypadkiem użycia, zastanawiam się, jak udało się to obejść? dzięki! – ultrajohn

Odpowiedz

4

Z mojego czytania dokumentacji Myślę, że istnieją dwa problemy:

  1. SecurityManager nie będą wykorzystywane do powiązanych obiektów (i wystąpienie django.db.models.Manager będzie używany zamiast)
  2. Możesz naprawić powyższe, ale dokumentacja przechodzi do wspaniałej lengths, aby określić, że funkcja get_query_set() nie powinna odfiltrowywać żadnych wierszy dla powiązanych zapytań.

Proponuję utworzyć funkcję, która pobiera QuerySet i stosuje odpowiedni filtr. To może być następnie użyte, gdy dojdziesz do QS przedmiotów i chcesz przetworzyć je dalej.

+0

Dziękuję za odpowiedź. 1. Przeczytałem dokumentację i byłem bardzo zaskoczony, gdy podczas 'items [0] .author.item_set.all()' Django nazywa się SecurityManager.get_query_set(). Nie prosiłem ich z use_for_related_fields. Ale to był jedyny kierownik tego modelu, może to ma znaczenie. 2. Tak, przeczytałem go, ale nadal uważam, że nie jest to mój przypadek, ponieważ naprawdę chcę, aby Django widział nie całą bazę danych, ale jej część. Prawdopodobnie postaram się jakoś zasugerować, ale moim pytaniem nie jest, jak odfiltrować nieistotne dane, ale aby filtrowanie było tak proste i tak automatyczne, jak to tylko możliwe. –