¿Vistas basadas en roles de Django?


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

Por ejemplo, el grupo de un usuario determinará a qué vistas/plantillas tendrá acceso. 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 es un hospital de enfermería unidad. Las enfermeras de una unidad no necesitan ver a todos los pacientes del hospital. Sólo necesitan ver a sus pacientes. Los médicos de la misma unidad solo necesitan ver a esos pacientes también, pero deben 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

Author: slypete, 2009-10-10

9 answers

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 /

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

Hay dos partes que usted necesita mirar.

  1. Compruebe que un usuario solicita una página tiene permiso haciéndolo.
  2. Solo muestra enlaces al usuario si tiene el permiso.

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

from django.contrib.auth.decorators import permission_required

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

Para 2. los permisos del usuario actualmente conectado se almacenan en la variable de plantilla {{ perms }}. Este código comprueba el mismo permiso que el anterior.

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

Para generar una lista de enlaces puede iterar sobre el usuario.get_all_permissions () y obtiene los enlaces (o función que genera el enlace) desde un dict:

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 muchos otros enfoques.

 41
Author: mbarkhau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-02 13:53:13

Hay un nuevo proyecto muy interesante sobre permisos basados en roles en Django: http://bitbucket.org/nabucosound/django-rbac

 5
Author: jujule,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-23 23:19:33

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

La forma en que lo hicimos fue la siguiente:

Cada objeto controlado por acceso tiene una relación ManyToMany con la tabla groups. Cada grupo se utilizó para definir un tipo específico de permiso ("puede ver lo básico 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, usted podría tener un grupo" valley-view-hospital").

Luego, cuando vaya a mostrar una lista de registros a un usuario, filtre en función de 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 separado de permisos negativos, o permisos de lectura/escritura separados. También puedes definir un conjunto de meta-grupos (médico, enfermero) que resulten en tu filtro de búsqueda recuperar el subconjunto real de permisos.

En cuanto a su problema de barra de enlaces, puede generarlos programáticamente usando el mismo filtro de sistema basado en las clases de objetos que el usuario puede ver o editar, y luego usar una función de tipo get_absolute_url() (tal vez llamarla get_index_url()) para devolver los enlaces para el índice de cada clase de objeto.

Debido a que todo esto es bastante complejo, probablemente terminarás queriendo hacer algún nivel de almacenamiento en caché para estas cosas, pero hazlo funcionar antes de molestarte optimizar. Es posible, y es menos feo en código que en palabras.

 4
Author: Paul McMillan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-29 06:01:03

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 está sugiriendo, utilizamos el sistema de permisos django para controlar las interacciones del usuario con los modelos. Sin embargo, no solo tratamos de agrupar usuarios, también agrupamos objetos a través de una GenericForeignKey.

Construimos un modelo que se vinculaba 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 creamos un modelo para servir como perfil de usuario del modelo de usuario de django. Todo lo que contenía era un campo ManyToMany vinculado al modelo de Grupo anterior. Esto nos permitió dar a los usuarios acceso a cero o más Grupos según sea necesario. (documentación )

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

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

 2
Author: Thomas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-30 04:23:28

Si no necesita ACL reales por objeto, entonces puede usar el sistema de permisos Django. Para obtener una lista de todos los permisos disponibles:

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

Existe una API para otras fuentes de autenticación y autorización, por lo que no es necesario seguir con esta tabla de permisos.

Puede hackear este sistema Django para satisfacer sus necesidades en términos de este modelo de autorización (RBAC) o puede llegar a una solución similar a ACL.

 1
Author: Andrey Vlasovskikh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-10 02:04:00

En un sitio para un experto en vino Pinot Noir creamos el acceso por objeto basado en 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 destacada, entonces el usuario obtuvo un 'token de bodega' que se expandió a todos los artículos, notas de cata, etc. relacionado con esa bodega. Utilizamos 'tokens con nombre' para regalar en eventos de degustación y dieron acceso a partes específicas del sitio. Incluso usamos esto para otorgar ciertos tipos de permisos para buscar engine spiders y luego asegúrese de que los enlaces que provienen de esos motores de búsqueda tengan los mismos permisos que la araña (es decir. no hay juegos de camuflaje).

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

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

 1
Author: Peter Rowell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-30 04:37:54

Puede usar los roles de usuario de django

Https://github.com/dabapps/django-user-roles

 1
Author: ecabuk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-07 13:59:13

Esta pregunta se hizo en Oct 2009 y el problema todavía existe en Julio 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 , vista Decoradores y Templatetag ; aparentemente django-permissions tiene todas ellas. Lee it's docs para su uso.

El único inconveniente es que está en desarrollo.

 1
Author: Soask,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-22 15:58:01

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

Las funciones de vista se decoraron:

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 obtuvo se establece dentro de un procesador de contexto. Los usuarios autenticados tienen un Rol, para las masas sin lavar un DummyRole.

El 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 previsto.

 0
Author: phoku,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-02 12:43:57