2012-04-22 5 views
6

Estoy tratando de implementar las características de Seguridad de Pyramid en mi sitio web, pero estoy teniendo problemas para encontrar la manera de usarlo.¿Cómo restrinjo los permisos basados ​​en el ID de una sola página en la URL?

He estado leyendo más de this tutorial y this example, así como los documentos de Pyramid, y no puedo encontrar la manera de implementar una política de autorización para los ID de una sola página.

Por ejemplo, tengo el siguiente esquema de URL:

/pages 
/pages/12 

/pages, obviamente, enumera las páginas disponibles y /pages/:id es donde se puede leer/comentario en la página.

La documentación/ejemplos que he leído han demostrado que puede implementar ACS de nivel grupal al proporcionar una devolución de llamada groupfinder con una lista de grupos. Como editor, admin, etc.

¿Cómo no puedo usar un grupo para permisos y, en su lugar, derechos basados ​​en el id de la página?

En mi esquema de URL anterior, cuando el usuario navega a /pages, debe haber iniciado sesión. Cuando navega a /pages/:id, debe tener acceso para ver esa identificación en particular. O bien, deben ser el propietario de esa página.

Igual que los comentarios. En la página /page/:id, es posible que se les haya dado acceso para ver la página pero no comentarla.

Respuesta

3

Para los fines de esta discusión, supongo que está utilizando SQLAlchemy para interactuar con su base de datos.

Si tiene config.add_route('pages', '/pages/{id}') en su __init__.py, se puede añadir una fábrica encargo para reemplazar/complementar su ACL predeterminada. Por ejemplo:

Su ACL actual puede tener este aspecto:

class RootFactory(object): 
    __acl__ = [ 
     (Allow, Everyone, 'view'), 
     (Allow, Authenticated, 'auth'), 
    ] 

    def __init__(self, request): 
     self.request = request 

Esto permitiría a los usuarios autenticados para acceder a cualquier punto de vista con un permiso de 'auth', y cualquier persona que visita su sitio para acceder a cualquier punto de vista con un permiso de 'ver'.

Al usar una fábrica personalizada , puede omitir su RootFactory o complementarlo.

Para omitir, cambiar su config.add_route original ->config.add_route('pages', '/pages/{id}', factory=PageFactory) y crear una clase PageFactory así:

class PageFactory(object): 
    __acl__ = [ 
     (Allow, Everyone, 'view'), 
     (Allow, Authenticated, 'auth'), 
    ] 

    def __init__(self, request): 
     self.request = request 

    from pyramid.security import authenticated_userid 
    user_id = authenticated_userid(self.request) 

    thispage = DBSession.query(Page).filter(Page.id==self.request.matchdict['id']).first() 

    if thispage.user_id == user_id: 
     ## Pyramid allows Everyone, Authenticated, and authenticated_userid 
     ## (each of these is known as a Principal) to be in the second 
     ## position of the ACL tuple 
     acl.append((Allow, user_id, 'edit')) 

Esto está asumiendo su punto de vista tiene permission='edit' como uno de sus parámetros.

Ahora, si desea utilizar el RootFactory y suplemento con su de fábrica personalizada, por lo que no tiene que repetirse, sólo tiene que dejar RootFactory como he mostrado en el comienzo de esta puesto, y heredar de la clase RootFactory, como tal:

class PageFactory(RootFactory): 
    @property 
    def __acl__(self): 
     acl = super(PageFactory, self).__acl__[:] ##[:] creates a copy 

     from pyramid.security import authenticated_userid 
     user_id = authenticated_userid(self.request) 

     thispage = DBSession.query(Page).filter(Page.id==self.request.matchdict['id']).first() 

     if thispage.user_id == user_id: 
      acl.append((Allow, user_id, 'edit')) 

     return acl 

el groupfinder es muy útil, por cierto, porque entonces se puede colocar simplemente los usuarios en grupos, como 'admin', y todos los que están en el grupo de administración pueden acceder a las vistas con permission='whatever' o permission='whateverelse' que desee y no se necesita en fábrica, solo un buscador de grupos que devuelve una lista de grupos para el usuario actual. Por desgracia, estoy divagando, ya que eso no es lo que estabas buscando hacer. Espero que esto responda a su pregunta.

6

El principio básico aquí es que la maquinaria de seguridad de Pyramid comprueba la ACL en el contexto actual. En este caso, su página sería el contexto lógico para usar. El primer paso es configurar una fábrica de contexto para una página. Suponiendo que está utilizando SQLAlchemy y el envío de URL, esto es simple de hacer. Registre su ruta como esta:

config.add_route('page', '/pages/{id:\d+}', factory=page_factory) 

Hay un pequeño truco en el camino de la ruta que hace pirámide comprobar el identificador de página debe ser un número por lo que no tiene que comprobar que usted mismo. Tenga en cuenta la referencia a un método * page_factory *. Vamos a definir ahora que:

def page_factory(request): 
    return DBSession.query(Page).get(int(request.matchdict['id'])) 

Esto toma el identificador de página de la ruta y que utiliza para buscar la página en su base de datos. Tenga en cuenta que no verificamos si el ID se puede convertir a un número entero aquí: podemos salirse con la nuestra ya que la ruta ya lo verifica directamente.

El siguiente paso es configurar la ACL en la página. La forma más sencilla es añadir un acl propiedad a que clase de página:

from pyramid import security 

class Page(BaseObject): 
    @property 
    def __acl__(self): 
     return [(security.Allow, self.userid, 'view')] 

Esta ACL dice pirámide que sólo se permite al usuario con el identificador almacenado en page.userid para ver esa página. Lo que es importante tener en cuenta aquí es que la ACL es diferente para cada página: se genera para cada página por separado en función de la información en su base de datos; en este caso usando self.userid.

Ahora puede utilizar la vista permiso en su vista:

@view_config(route_name='page', context=Page, permission='view') 
def page_view(context, request): 
    return 'I can see!' 

Este ejemplo tiene una ACL muy mínimo para una página, pero se puede extender el proceso a satisfacer sus necesidades.

También tenga en cuenta el contexto = parámetro de página para view_config: esto le dice a la pirámide que esta vista solo debe usarse para el contexto es una página. Si la fábrica de contexto (page_factory en este ejemplo) no encontró una página que coincida, devolverá None en lugar de una instancia de página, por lo que esta vista no será utilizada por pyramid. Como resultado, la pirámide producirá automáticamente un error no encontrado.

+0

pequeño nitpick, si su fábrica raíz devuelve 'None', entonces el contexto es' None', 404 no se producirá automáticamente a menos que no se pueda encontrar una vista. En su ejemplo, se encontraría 'page_view', pero se prohibiría debido al contexto' None' que no tiene '__acl__'. –

+0

Finalmente se hace clic. Hasta el día de hoy, no veía ninguna relación entre la clase de página con la ACL y la 'clase de tabla' de SQLAlchemy Page. Todo comienza a formarse ahora. – Kane

+0

Michael: buen punto. Una forma de obtener ese comportamiento es agregar context = Page en la invocación view_config. Actualizaré mi respuesta para reflejar eso. –

Cuestiones relacionadas