2011-10-24 4 views
8

Je n'ai vraiment aucune idée du fonctionnement d'ACL. Je sais que c'est plutôt cool et que ça pourrait me faire gagner beaucoup de temps et de douleur. Mais actuellement je suis un peu perdu. Tous les exemples de pyramides utilisent la traversée. J'utilise exclusivement l'envoi d'URL. Je ne suis pas sûr de comprendre comment je peux construire une arborescence de ressources.Pyramid ACL sans traversée

Voici un exemple de code:

class QuestionFactory(object): 

    def __init__(self, request): 
     self.__acl__ = default[:] 
     self.uid = authenticated_userid(request) 

     self.qid = request.matchdict.get('id') 
     if self.qid: 
      self.question = request.db.questions.find_one({'_id': ObjectId(self.qid)}) 
      if str(self.question.get('owner')) == self.uid: 
       self.__acl__.append((Allow, userid, 'view'))  

La chose est que, cela fonctionne. Mais je dois définir une nouvelle usine pour chaque type de ressource. Je ne suis pas certain de savoir comment je suis censé savoir à quelle ressource j'essaie d'accéder via URL Dispatch et Factory. Je vois quelque chose comme ça

/accounts/{account} //Owners only but viewable by anyone 
/messages/{message} //Owners only 
/configs/{config}  //Admin only 
/pages/{page}   //Admins only but viewable by anyone 

Cela dit ici, j'aurais une telle structure

Root -\ 
     +-- account 
     +-- message 
     +-- config 
     +-- page 

Chacun de ces usine a sa propre acl spéciale. L'autre chose est que/comptes est la page principale. Il n'a pas d'identifiant ou quoi que ce soit. Aussi/accounts/new est aussi un cas particulier. Ce n'est pas un identifiant mais l'idée de créer un nouvel objet. J'utilise un style reposant avec l'exigence GET/PUT/DELETE/POST. Je ne suis pas sûr de savoir comment je suis censé faire correspondre l'URL à une ressource et à la bonne ACL automatiquement. Si je définis dans ma racine une usine spéciale comme ci-dessus, il n'y a pas de problèmes.

modifier

Je ne l'ai eu à travailler à l'exception de certaines choses. Je pense finalement que je comprends quel est le but de la traversée. Par exemple avec nous avons cet url:/comments/9494f0eda/new, /comments/{comment}/new

Nous pourrions avoir à Node dans notre arbre de ressources ou même 3 nœuds.

La RootFactory sera inspectée en premier, puis selon notre parcours. Il obtiendra le commentaire attribut de RootFactory, puis « commentaire » de l'usine de commentaires et la « nouvelle » de CommentFactory ou de l'objet lui-même

Je ne l'utilise pas d'usine comme dict comme dans l'exemple de Michael

Il ressemble beaucoup à ça:

class RessourceFactory(object): 
    def __init__(self, parent, name): 

     self.__acl__ = [] 
     self.__name__ = name 
     self.__parent__ = parent 

     self.uid = parent.uid 
     self.locale = parent.locale 
     self.db = parent.db 
     self.req = parent.req 

Ceci est mon objet de base. À chaque pas, il copie l'information du parent au nouvel enfant. Je pourrais certainement faire exploser mon attribut ... le contexte. parent ._ parent _.uid mais ce n'est pas génial.

La raison pour laquelle je n'utilise pas l'attribut dict. J'ajoute de faire cela fonctionne avec

/Commentaires

Pour certaines raisons, il a fait créer mon CommentFactory mais il n'a pas retourné comme il n'y avait pas besoin d'une clé.

Donc, ma racine usine à peu près ressembler à ceci:

si aucun élément
class RootFactory(object): 

    def __init__(self, request): 
     self.__acl__ = default[:] 

     self.req = request 
     self.db = request.db 

     self.uid = authenticated_userid(request) 
     self.locale = request.params.get('locale', 'en') 

    def __getitem__(self, key): 

     if key == 'questions': 
      return QuestionFactory(self, 'questions') 
     elif key == 'pages': 
      return PageFactory(self, 'pages') 
     elif key == 'configs': 
      return ConfigFactory(self, 'configs') 
     elif key == 'accounts': 
      return AccountFactory(self, 'accounts') 

     return self 

se trouve, RootFactory se retourner sinon, il retourne une nouvelle usine. Puisque je base mon code sur le code de Michael, il y a un second paramètre pour le constructeur de Factory. Je ne suis pas certain de le garder comme QuestionFactory est bien conscient de gérer les "questions" donc il n'est pas nécessaire de nommer l'usine ici. Il devrait déjà connaître son nom.

class QuestionFactory(RessourceFactory): 
    def __init__(self, parent, name): 
     RessourceFactory.__init__(self, parent, name) 
     self.__acl__.append((Allow, 'g:admin', 'view')) 
     self.__acl__.append((Allow, 'g:admin', 'edit')) 
     self.__acl__.append((Allow, 'g:admin', 'create')) 
     self.__acl__.append((Allow, 'g:admin', 'delete')) 
     self.__acl__.append((Allow, Everyone, 'create')) 

    def __getitem__(self, key): 

     if key=='read': 
      return self 

     self.qid = key 
     self.question = self.db.questions.find_one({'_id': ObjectId(self.qid)}) 

     if str(self.question.get('owner')) == self.uid: 
      log.info('Allowd user %s' % self.uid) 
      self.__acl__.append((Allow, self.uid, 'view')) 
      self.__acl__.append((Allow, self.uid, 'edit')) 
      self.__acl__.append((Allow, self.uid, 'delete')) 

     return self 

Voilà où presque toute la logique ira. Dans le initialisation je mis acl qui fonctionnera pour/questions dans le getitem cela fonctionnera pour/questions/{id}/*

Depuis que je se retourne, tout getitem passé ce RessourceFactory pointera vers lui-même si je reviens une nouvelle usine pour un cas particulier. La raison en est que mon contexte n'est pas seulement un objet dans la base de données ou un objet.

Mon contexte gère plusieurs choses comme l'ID utilisateur, les paramètres régionaux et ainsi de suite ... lorsque l'acl est terminé, j'ai un nouvel objet de contexte prêt à l'emploi. Il supprime la plupart de la logique dans les vues.

Je pourrais probablement définir des événements pour interroger les paramètres régionaux et l'uid, mais cela correspond vraiment ici. Si j'ai besoin de quelque chose de nouveau, il me suffit d'éditer mon RootFactory et RessourceFactory pour les copier dans une factory enfant. De cette façon, si quelque chose doit changer à travers toutes les vues, il n'y a pas de redondance du tout.

Répondre

5

Il semble que vous soyez intéressé par certaines fonctionnalités de sécurité au niveau de l'objet/de la ligne pour permettre uniquement aux propriétaires de comptes d'afficher leurs données. Je vous renvoie à ma réponse SO précédente sur ce sujet, ainsi que le tutoriel sur lequel j'ai travaillé pour auth dans URL Dispatch qui est construit autour de cette réponse. Plus précisément, vous pourriez vouloir regarder la démo 2.object_security dans le projet github lié ainsi que les docs expliquant les arborescences de ressources dans le cadre du rendu html sur mon site.

Pyramid authorization for stored items

https://github.com/mmerickel/pyramid_auth_demo

http://michael.merickel.org/projects/pyramid_auth_demo/

Si vous avez des questions à comprendre ces ressources que je serais heureux d'élaborer davantage ici.

+0

Je ne sais pas, j'ai déjà tous lu ça. Comme je l'ai dit dans le titre ... J'essaie d'y parvenir sans traverser. J'ai essayé une fois et ça a foiré mes routes et rien n'a marché. Je ne crois pas que j'ai une hiérarchie d'arbres aussi. puisque j'ai des pages, des messages, etc., mais aucun objet ne se rapporte vraiment à un autre. Donc une telle chose/foo/bar/baz ne me parle pas beaucoup. –

+0

J'ai fait quelques tests et ça pourrait marcher après tout ... Je vais écrire quelque chose demain je dois dormir avant mon examen demain. –

+0

Les liens que je vous ai donnés utilisent l'envoi d'URL ... le système d'authentification de pyramid fonctionne hiérarchiquement en traversant une arborescence d'objets. C'est ainsi que fonctionne ACLAuthorizationPolicy. Je serais surpris si vous "liez déjà tout ça" parce que je viens de réécrire cette démo la nuit dernière et je travaille activement dessus. ;-) –