J'essaie d'implémenter des contrôles de sécurité basés sur les lignes pour les modèles Django. L'idée est que lorsque j'accède au gestionnaire de modèles, je spécifie des informations supplémentaires qui sont utilisées dans les requêtes de base de données, de sorte que seules les instances autorisées sont extraites de la base de données. Par exemple, nous pouvons avoir deux modèles: Utilisateurs et, disons, Articles. Chaque article appartient à un utilisateur et l'utilisateur peut être connecté à plusieurs articles. Et laissez-y quelques restrictions, selon lesquelles un utilisateur peut voir ou ne pas voir les articles d'un autre utilisateur. Je veux séparer ces restrictions d'autres éléments de la requête et écrire quelque chose comme:Modèles Django - transmettre des informations supplémentaires au gestionnaire
items = Item.scoped.forceRule('user1').all() # all items visible for 'user1'
ou
# show all items of 'user2' visible by 'user1'
items = Item.scoped.forceRule('user1').filter(author__username__exact = 'user2')
Pour acheive cela, je fait ce qui suit:
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)
Pour des exemples présentés, il fonctionne très bien , mais meurt le suivant:
items = Item.scoped.forceRule('user1').filter(author__username__exact = 'user2') # (*)
items2 = items[0].author.item_set.all() # (**)
Certainement, items2
est rempli par tous les éléments de 'user2', pas seulement ceux qui sont conformes à la règle. En effet, lorsque la commande all() est exécutée, SecurityManager.get_query_set()
ne contient aucune information sur l'ensemble de restrictions. Bien que ça puisse. Par exemple, dans forceRule(), je pourrais ajouter un champ pour chaque instance et ensuite, si je pouvais accéder à ce champ depuis le gestionnaire, appliquer la règle nécessaire. Donc, la question est - est-il un moyen de passer un argument fourni à forceRule()
dans l'instruction (*)
au gestionnaire, appelé dans l'instruction (**)
.
Ou une autre question - est-ce que je fais des choses étranges que je ne devrais pas faire du tout?
Merci.
Je suis confronté au même cas d'utilisation aussi, je me demande comment vous avez réussi à contourner cela? Merci! – ultrajohn