2011-10-24 15 views
8

Realmente no tengo idea de cómo funciona ACL. Sé que es genial y podría ahorrarme mucho tiempo y dolor. Pero actualmente estoy un poco perdido. Todo el ejemplo de pirámide usa cruce. Uso exclusivamente el despacho de URL. No estoy seguro de entender cómo puedo construir una estructura de árbol de recursos.Pyramid ACL without traversal

Este es un ejemplo de código:

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'))  

El caso es que, funciona. Pero tengo que definir una nueva fábrica para cada tipo de recurso. No estoy seguro de cómo se supone que debo saber a qué recurso estoy intentando acceder a través del envío de URL y la fábrica. Que vería algo así

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

Dicho esto aquí que tendría dicha estructura

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

Cada uno de estos fábrica tiene su propia ACL especial. La otra cosa es que/accounts es la página principal. No tiene una identificación ni nada. También/accounts/new es también un caso especial. No es una identificación, sino la vista para crear un nuevo elemento.

Estoy usando un estilo relajante con el requisito GET/PUT/DELETE/POST. No estoy tan seguro de cómo debo unir la url a un recurso y al acl correcto automáticamente. Si defino en mi raíz una fábrica especial como la anterior, no hay problemas.

edición

Yo tengo que trabajar con la excepción de algunas cosas. Finalmente creo que entiendo cuál es el propósito de la poligonal. Por ejemplo, tenemos esa url:/comments/9494f0eda/new, /comments/{comment}/new

Podríamos tener que Node en nuestro árbol de recursos o incluso 3 nodos.

Primero se inspeccionará RootFactory, luego según nuestro recorrido. Se obtendrá el atributo de comentarios RootFactory, a continuación, "comentario" de la fábrica de comentario y la "nueva" de CommentFactory o del objeto mismo

No consumo fábrica como dict como en el ejemplo de Michael

se se parece mucho a eso:

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 

Este es mi objeto ressource base. En cada uno de los pasos, copia información del padre al nuevo hijo. Ciertamente podría crear una burbuja en mi atributo ... contexto. padre ._ padre _.uid pero eso no es tan bueno.

La razón por la que no estoy usando el atributo dict. Añado para hacerlo trabaja con

/Comentarios

Por algunas razones, se hizo crear mi CommentFactory pero no se la devolvió, ya que no había necesidad de una llave.

Así que mi fábrica raíz más o menos el siguiente aspecto:

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 

si no se encuentra ningún elemento, RootFactory volver en sí, si no, se devuelve una nueva fábrica. Como base mi código en el código de Michael, hay un segundo parámetro para el constructor de Factory. No estoy seguro de mantenerlo, ya que QuestionFactory es muy consciente de manejar "preguntas", por lo que no es necesario que nombre la fábrica aquí. Ya debería saber su nombre.

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 

Así que ahí es donde irá casi toda la lógica. En el init puse acl que funcione para/preguntas en el GetItem va a trabajar para/preguntas/{id}/*

Desde vuelvo en sí, cualquier GetItem más allá de este RessourceFactory apuntará a sí mismo a menos que vuelva una nueva fábrica para algún caso especial. La razón por la cual hacerlo es porque mi contexto no es solo un objeto en la base de datos o un objeto.

Mi contexto maneja múltiples cosas como ID de usuario, configuración regional, etc. ... cuando se completa el acl, tengo un nuevo objeto de contexto listo para usar. Elimina la mayor parte de la lógica en las vistas.

Probablemente podría establecer eventos para consultar locale y uid, pero realmente se ajusta aquí. Si necesito algo nuevo, solo tengo que editar mi RootFactory y RessourceFactory para copiarlos a fábrica infantil.

De esta forma, si algo tiene que cambiar en todas las vistas, no hay redundancia en absoluto.

Respuesta

5

Parece que le interesan algunas características de seguridad de objetos/filas para permitir que solo los propietarios de las cuentas puedan ver sus datos. Me gustaría referirme a mi respuesta SO anterior sobre este tema, así como el tutorial en el que he estado trabajando para auth en el despacho de URL, que se basa en esta respuesta. Específicamente, es posible que desee consultar la demostración 2.object_security en el proyecto github vinculado, así como los documentos que explican árboles de recursos como parte del html representado en mi sitio.

Pyramid authorization for stored items

https://github.com/mmerickel/pyramid_auth_demo

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

Si usted tiene alguna pregunta comprensión de esos recursos que estaría feliz de dar más detalles aquí.

+0

No lo sé, ya lo leí. Como dije en el título ... Estoy tratando de lograr esto sin atravesarlo. Intenté una vez y estropeó mis rutas y nada funcionó. No creo que tenga ninguna jerarquía de árbol también. ya que tengo páginas, mensajes, etc., pero ningún objeto se relaciona realmente entre sí. Entonces tal cosa/foo/bar/baz no me habla mucho. –

+0

Hice algunas pruebas y podría funcionar después de todo ... Escribiré algo mañana. Tengo que dormir antes de mi examen mañana. –

+0

Los enlaces que te di están usando el envío de URL ... el sistema de autenticación de pyramid funciona jerárquicamente al atravesar un árbol de objetos. Así es como funciona ACLAuthorizationPolicy. Me sorprendería si "ya leíste todo eso" porque ayer volví a escribir esa demo y estoy trabajando activamente en ello. ;-) –