2009-10-10 32 views
25

Estoy buscando información sobre cómo otros podrían diseñar esto. Voy a proporcionar vistas basadas en la clase (grupo django).Vistas basadas en roles Django?

Por ejemplo, el grupo de un usuario determinará qué puntos de vista/plantillas de él o ella tendrá acceso a. Estoy pensando en quizás almacenar rutas para ver funciones en una tabla para determinar en qué consistirá la barra de enlaces de un usuario. Las especificaciones del filtro también se pueden almacenar para determinar qué filas llenarán estas plantillas.

Un buen ejemplo son las unidades de enfermería de un hospital. Las enfermeras de una unidad no necesitan ver a todos los pacientes del hospital. Solo necesitan ver a sus pacientes. Los doctores en la misma unidad solo necesitan ver a esos pacientes también, pero deberían tener acceso a una funcionalidad mucho mayor.

se ha hecho esto a través de alguna aplicación de terceros? ¿Y cómo abordarías este problema?

Gracias, Pete

+1

Guys, el sistema de permiso de Django no se ajusta a mis necesidades. Es por eso que estoy pidiendo ayuda de arquitectura: P – slypete

Respuesta

38

Django ya tiene un sistema de grupos y permisos, que puede ser suficiente para su propósito.

http://docs.djangoproject.com/en/dev/topics/auth/

general en su código que comprobar si un usuario tiene un permiso. Un usuario tiene sus propios permisos y los de los grupos a los que pertenece. Puede administrar esto bastante fácilmente desde la consola de administración.

Hay dos piezas que necesita para mirar.

  1. Compruebe que un usuario que solicite una página tiene permiso para hacerlo.
  2. sólo muestran vínculos con el usuario si tiene el permiso.

Para 1. puede comprobar permisos en un decorador como tal:

from django.contrib.auth.decorators import permission_required 

@permission_required('polls.can_vote') 
def some_view(request): 

Por 2. los permisos del usuario que ha iniciado sesión en se almacenan en la variable de plantilla {{}} permanentes. Este código verifica el mismo permiso que el anterior.

{% if perms.polls.can_vote %} 
    <a href="/vote">vote</a> 
{% endif %} 

para generar una lista de enlaces que puede iterar sobre user.get_all_permissions() y sacar los enlaces (o función que genera el enlace) a partir de un diccionario:

def more_elaborate_list_of_links_for_a_perm(user): 
    return ["/link1", ...] 

_LINKS = { 
    'polls.can_vote' : lambda u: ["/user/specific/link/" + u.id], 
    'polls.can_close': lambda u: ['/static/link/1', 'static/link/2'], 
    'polls.can_open' : more_elaborate_list_of_links_for_a_perm 
} 

def gen_links(user): 
    # get_all_permissions also gets permissions for users groups 
    perms = user.get_all_permissions() 
    return sum((_LINKS[p](user) for p in perms if p in _LINKS), []) 

Probablemente hay muchas otras enfoques.

+1

¿Cómo generaría una lista de enlaces para proporcionarle a un usuario el uso del sistema de permisos integrado de django? – slypete

+1

Para el registro, no seleccioné esta respuesta como la mejor. Yo no creo que sea – slypete

1

Si usted no necesita reales LCA por objeto, a continuación, puedes utilizar el sistema de permisos de Django. Para obtener una lista de todos los permisos disponibles:

from django.contrib.auth.models import Permission 
perms = Permission.objects.all() 

Hay un API for other authentication and authorization sources, por lo que no es necesario seguir con esta tabla de permisos.

Usted puede cortar este sistema Django para satisfacer sus necesidades en términos de este modelo de autorización (RBAC) o puede llegar a una solución de ACL-similares.

+0

¿Alguna pista para un acl por objeto? – gpilotino

4

Tuvimos un problema similar. Los grupos de Django no son REALMENTE adecuados para esto, pero puedes calzarlos en.

La forma en que lo hicimos fue de la siguiente manera:

Todos los objetos de acceso controlado tiene una relación ManyToMany a la mesa grupos. Cada grupo se usó para definir un tipo específico de permiso ("puede ver los conceptos básicos del paciente", "puede editar la información de contacto del paciente", etc.). Los usuarios se agregan a los grupos para los que deberían tener permisos (en su ejemplo de ver solo pacientes en este hospital, podría tener un grupo "valley-view-hospital").

Luego, cuando va a mostrar una lista de registros a un usuario, filtra según la conjunción de los dos grupos. Un usuario debe tener todos los permisos de grupo asociados para ver un objeto determinado.

Si su sistema lo requiere, puede mantener un ManyToMany de permisos negativos por separado o permisos de lectura/escritura separados. También podría definir un conjunto de metagrupos (médico, enfermera) que hagan que su filtro de búsqueda recupere el subconjunto real de permisos.

En cuanto a su problema de enlace de barras va, puede generar los programáticamente utilizando el mismo sistema - filtro en función de las clases de objetos que el usuario puede ver o editar, y luego utilizar una función get_absolute_url() tipo (tal vez llamarlo get_index_url()) para devolver los enlaces para el índice de cada clase de objeto.

Como todo esto es bastante complejo, probablemente termines queriendo hacer un cierto nivel de almacenamiento en caché para estas cosas, pero hazlo funcionar antes de que te molestes en optimizarlo. Es posible, y es menos feo en el código que en palabras.

+0

He terminado yendo por esta ruta con nuestra aplicación, pero no es ideal. Descubrí que el rendimiento ha disminuido un poco. Estoy buscando otro lugar para una mejor solución de ACL – Gevious

+0

Esto no es escalable en absoluto. ¿Alguna idea sobre ACL? – user710907

2

Tuve un problema similar no hace mucho tiempo. Nuestra solución hizo el truco, aunque podría ser demasiado simple para su situación. Como todo el mundo sugiere, utilizamos el sistema de permisos django para controlar qué interacciones del usuario con los modelos. Sin embargo, no solo tratamos de agrupar a los usuarios, también agrupamos objetos a través de GenericForeignKey.

Creamos un modelo que se vincula a sí mismo para permitir el desarrollo de jerarquías.

class Group(models.Model): 
    name = models.CharField(...) 
    parent = models.ForeignKey('self', blank=True, null=True) 
    content_type = models.ForeignKey(ContentType) 
    object_id = models.PositiveIntegerField() 
    content_object = generic.GenericForeignKey('content_type', 'object_id') 
    ... 

Para que funcione, también hemos creado un modelo para servir como perfil de usuario del modelo de usuario Django. Todo lo que contenía era un ManyToManyField vinculado al modelo de Grupo anterior. Esto nos permitió brindar a los usuarios acceso a cero o más grupos según sea necesario. (documentation)

class UserProfile(models.Model): 
    user = models.ForeignKey(User, unique=True) 
    groups = models.ManyToManyField(Group) 
    ... 

Esto nos dio lo mejor de ambos mundos y nos mantuvo de tratar de meter con calzador todo en el sistema de autorización de Django. Estoy usando esta configuración básica para controlar el acceso del usuario al contenido deportivo (algunos usuarios pueden acceder a ligas completas, algunas a una o dos conferencias, algunas solo tienen acceso a equipos individuales) y funciona bien en esa situación. Probablemente podría ser lo suficientemente generalizado como para satisfacer sus necesidades.

1

En un sitio para un experto en vino Pinot Noir creamos acceso por objeto en función de una serie de criterios diferentes. Si el enlace entrante tenía un campo de referencia que coincidía con el nombre de dominio de una bodega presentada, entonces el usuario obtenía una "ficha de bodega" que se ampliaba a todos los artículos, notas de cata, etc. relacionados con esa bodega. Usamos 'tokens con nombre' para obsequiar eventos de degustación y dieron acceso a partes específicas del sitio. Incluso usamos esto para otorgar ciertos tipos de permisos a las arañas de los motores de búsqueda y luego nos aseguramos de que los enlaces que provienen de esos motores de búsqueda tengan los mismos permisos que la araña (es decir, sin juegos de encubrimiento).

La versión corta es que puede crear una clase (los llamamos TokenBuckets que contienen Tokens) y cada objeto (en una página de detalles, o una lista, o lo que sea) puede preguntar al TokenBucket del usuario si un cierto nivel de el acceso está permitido

Básicamente es un tipo raro de sistema de ACL. No fue tan difícil crear la mecánica. Toda la magia está en determinar bajo qué circunstancias los tokens entran en el cubo.

0

Utilizamos un sistema de base de roles para un problema similar. Básicamente los usuarios tienen permisos para asumir roles diferentes.

Ver funciones se han decorado:

def needs_capability(capability,redirect_to="/cms/"): 
    def view_func_wrapper(view_func): 
     def wrapped_view_func(request,*args,**kwargs): 
      if not request.role._can(capability): 
       return HttpResponseRedirect(redirect_to) 
      return view_func(request,*args,**kwargs) 
     return wrapped_view_func 
    return view_func_wrapper 

El resto de la magia está dentro del atributo request.role que consiguió conjunto dentro de un procesador de contexto. Los usuarios autenticados obtuvieron un Rol, para las masas sin lavar un DummyRole.

acceso a la información se restringió aún más dentro de las plantillas:

{% if not request.role.can.view_all_products %} 
      Lots of products, yeah! 
{% endif %} 

No es la solución más limpia en mi opinión, pero funcionó como se esperaba.

1

Esta pregunta se ha hecho en Oct 2009 y el problema todavía existe en de julio de 2012.

He buscado una buena aplicación basada en roles, y encontré django-permission como el mejor resultado.

tres características importantes que necesitaba eran Roles, ver decoradores y Templatetag; aparentemente django-permissions tiene todos ellos. Lea que es docs para su uso.

El único inconveniente es que está en desarrollo.

Cuestiones relacionadas