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.
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. –
Hice algunas pruebas y podría funcionar después de todo ... Escribiré algo mañana. Tengo que dormir antes de mi examen mañana. –
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. ;-) –