Permisos y Grupos de Permisos con Django

Permisos y Grupos de Permisos con Django

Un tema fundamental de todo sistema son los Permisos y los distintos Roles que un usuario puede tener dentro de él, para esto, en este post se explicará como funcionan los Permisos y los Grupos de Permisos con Django.

Por lo tanto en este post hablaremos de:

  • El modelo Usuario
  • Permisos
  • Grupos de Permisos

Pero antes de hablar sobre estos temas, debemos conocer la diferencia entre 2 temas que podemos confundir, Autenticación y Autorización.

AUTENTICACIÓN es la acción de iniciar Sesión dentro de un sistema, página web, etc.

AUTORIZACIÓN son las acciones que el usuario que ha realizado una Autenticación dentro del sistema tiene permitido realizar.

Permisos y Grupos

Los permisos son aquellos que se utilizan para validar Autorización, es decir, a través de ellos podemos decidir que es lo que dejamos que un usuario puede realizar, mientras que un Grupo es un conjunto de permisos que se utilizan para encapsular un Rol, por ejemplo, dentro de una Farmacia, existen roles, como Cajero, Botiquero, Ingeniero Químico, etc, cada uno de ellos tendrá permisos comunes y permisos no comunes, los cuales podemos agrupar y representar por Roles dentro del sistema, haciendo un abstracción mas real de los mismos.

Para usar tanto Permisos y Grupo de Permisos dentro de Django, si utilizamos el modelo User que trae por defecto el framework, no debemos agregarle nada en especial, pero si hemos creado nuestro propio modelo User debemos agregarle la herencia de AbstractUser para acceder a los métodos y atributos que permitirán utilizarlos.

Debemos saber que Django agrega permisos por defecto cuando se ha añadido django.contrib.auth en nuestro INSTALLED_APPS de nuestro archivo SETTINGS del proyecto, viene agregado por defecto y si lo dejamos así Django inmediatamente cada vez que creemos un nuevo Modelo y realicemos la migración a la Base de Datos, creará 4 permisos base, add,change,delete,view con la siguiente estructura.

nombre aplicacion.(add o delete o view o change)_nombre_modelo

Por ejemplo, polls.add_vote, donde polls es el nombre de la aplicación dentro del proyecto de Django, vote es el nombre del modelo.

Usando Permisos

Para validar un permiso con el modelo User de Django, ya sea Personalizado y el por defecto, podemos utilizar el método has_perm de este mismo, por ejemplo:

user.has_perm('libro.add_libro')

user.has_perm('libro.change_libro')

user.has_perm('libro.delete_libro')

user.has_perm('libro.view_libro')

Si queremos comprobar si el usuario tiene el Permiso antes de que acceda al código de nuestra función o Vista, podemos utilizar el decorador permission_required de la siguiente forma:

from django.contrib.auth.decorators import permission_required

@permission_required('libro.add_libro') 
def your_function(request):
    pass

Si lo que queremos es validar los permisos dentro de nuestro Template, siempre y cuando se esté utilizando el Sistema de Plantillas de Django, lo podemos realizar de la siguiente forma:

{% if perms.libro.add_libro %}

Es decir, la sintaxis {% if perms.app_label.can_do_something %}

Si lo que queremos realizar es Añadir, Remover, Cambiar uno o mas permisos de nuestro usuario, podemos utilizar los siguientes métodos:

# Para cambiar los permisos de nuestro usuario
user.user_permissions.set([permission_list])

# Para agregar uno o mas permisos a nuestro usuario
user.user_permissions.add(permission, permission, ...)

# Para remover uno o mas permisos a nuestro usuario
user.user_permissions.remove(permission, permission, ...)

# Para quitar todos los permisos que nuestro usuario tenga
user.user_permissions.clear()

Debemos saber que el modelo Usuario por defecto o personalizado heredando de AbstractUser tiene una relación de ManyToManyField con el modelo de Django llamado Permission, este campo de relación se llama user_permissions, por ello es que se utiliza en el ejemplo anterior y por ello para visualizar los permisos que tenga nuestro usuario debemos realizar una consulta con el ORM, por ejemplo:

user.user_permissions.all()

Personalizando Permisos

Si lo que quieres es agregar tus propios permisos puedes hacerlo de varias maneras, la primera es directamente dentro de tu modelo, utilizando la clase Meta que todo Modelo de Django tiene, definiéndolos dentro del atributo permission:

from django.db import models 

class Libro(models.Model):

        # atributos del modelo  

        class Meta:
        permissions = (
                       ("view_libro_reservado", "Puede ver libro reservado"),
                      )

Ahora si lo que quieres es crear un permiso en algún otro lado de forma personalizada, puedes utilizar la clase Permission y crear un nueva instancia de ella para que se registre.

from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType

content_type = ContentType.objects.get_for_model(Libro)
new_permission = Permission.objects.create(
                 codename='can_ver_reserva',
                 name='Puede ver reserva',
                 content_type=content_type,
)

ContentType es un modelo que crea una instancia de cada modelo existente en el Proyecto, para definir internamente que cada Modelo sea un tipo de Dato dentro del proyecto, este modelo ContentType es quien se enlaza con Permission, por esto se utiliza en el ejemplo anterior.

Algo que tenemos que tener en cuenta es que un usuario de tipo SUPERUSUARIO accederá a todos los permisos sin necesidad de habérselos agregado.

Usando Grupo de Permisos

Al igual que con los Permisos individuales, el modelo User de Django, siempre y cuando tenga herencia de AbstractUser tendrá un atributo llamado groups del tipo ManyToManyField con el modelo de Django Group, el cual tiene una relación del mismo tipo con la clase Permission de Django.

Por ejemplo, si queremos consultar la existencia de un grupo, podemos realizarlo de la siguiente manera:

from django.contrib.auth.models import Group
bibliotecario_group, created = Group.objects.get_or_create(name='Bibliotecario')

Para Asignar, Remover, Editar los permisos que tiene asociados un Grupo, podemos utilizar la misma sintaxis que con los Permisos.

bibliotecario_group.permissions.set([permission_list])
bibliotecario_group.permissions.add(permission, permission, ...)
bibliotecario_group.permissions.remove(permission, permission, ...)
bibliotecario_group.permissions.clear()

Para asignar un Grupo a un usuario lo hacemos de la siguiente manera:

# A través de relación inversa
bibliotecario_group.user_set.add(user)

# A través de relación directa       
user.groups.add(bibliotecario_group)

Si deseas validar si un usuario pertenece a un grupo, lo puedes hacer de la siguiente manera:

user.groups.filter(name='Bibliotecario').exists()

Si deseas hacer una validación de Grupo de permisos pero desde tus Templates utilizando el Sistema de Plantillas de Django, deberás crear un templatetag, mas o menos de la siguiente manera:

from django import template

register = template.Library() 

@register.filter(name='has_group') 
def has_group(user, group_name):
    return user.groups.filter(name=group_name).exists() 

Y en tu template colocar:

{% if request.user|has_group:"Bibliotecario" %} 
    <p>User belongs to my group 
{% else %}
    <p>User doesn't belong to mygroup</p>
{% endif %}

Si quieres ver un ejemplo práctico completo, te dejo un vídeo al canal de un miembro de la comunidad, Developer.pe, donde explica todo esto, de igual puedes revisar la documentación oficial de Django para más información.

Escribe un comentario

Nombre
Apellido