Introducción

Este post es el complemento del artículo Sistema de Permisos en Django. No es una introducción a Django restframework, más bien es como implementar el sistema de autorización y autenticación en este framework.

Autorización

Se usa el mismo sistema de grupos de Django que ya se describió en el post anterior:

Autenticación y autorización

Autenticación

Aquí tenemos dos opciones, usar la autenticación por nombre de usuario y contraseña de Django, o implementar otro método como JSON Web Token (JWT). Independientemente del sistema que usemos, el proceso para la autenticación es el mismo.

Usar nombre de usuario y contraseña

Si nos vamos por este camino no tenemos que hacer nada extra, ya que es el modo predeterminado de restframework.

JWT

La implementación de los JSON Web Token es muy sencilla. Primero tenemos que agregar la dependencia del paquete simplewjt en nuestro requirements.txt:

djangorestframework==3.11.0
coreapi==2.3.3
djangorestframework_simplejwt==4.4.0

Notas: 1) Dependiendo de la organización de tu proyecto, las dependencias pueden estar en otro archivo, en cookiecutter-django este archivo es base.txt, por dar un ejemplo. 2) Los números de versiones de las dependencias pueden variar en base a cuando leas este post.

Ahora hay que registrar a simplejwt en nuestro archivo de configuración settings.py (o base.py, ver notas arriba):

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ]
}

Y esto es todo lo que tenemos que configurar para empezar a usar JWT.

Vistas de la aplicación

Vamos a reusar las vistas del post Sistema de Permisos en Django, y las modificaremos para usar la autenticación de restframework. La principal diferencia es que la autenticación y autorización ya no se especifican como Mixin al declarar la vista, ahora se usa la variable de clase permission_classes este propósito. Aun así podemos crear una clase que gestione la autorización:

from rest_framework import permissions


class BaseAuthPermApi(permissions.BasePermission):
    def has_permission(self, request, view):
        for grupo in request.user.groups.all():
            if grupo.name in self._PERMISSIONS:
                return True
        return False

Cuando usamos restframework el método para la autorización cambia de test_func() a has_permissions(), aunque su implementación es la misma. También es innecesario crear una función que nos regrese una url para el login, como lo hacíamos con get_login_url(). Ahora podemos implementar una clase con los permisos que necesitemos:

from my_auth import BaseAuthPermApi
from django.views.generic import ListView, TemplateView
from .models import SupervisorVendedor, Venta


class PermisoGerente(BaseAuthPermApi):
    _PERMISSIONS = ['GERENTE']


class PermisoSupervisor(BaseAuthPermApi):
    _PERMISSIONS = ['VENDEDOR', 'SUPERVISOR']


class IndexView(TemplateView)
    template_name = 'homepage.html'
    

class VentasView(ListView):
    permission_classes = [PermisoGerente & permissions.IsAuthenticated]
    model = Venta
    template_name = 'ventas/ventas_sin_filtro.html'
    

class VentasFiltradasView(ListView):
    permission_classes = [PermisoSupervisor & permissions.IsAuthenticated]
    template_name = 'ventas/ventas_con_filtro.html'

        
    def get_queryset(self):
        grupos = self.request.user.groups.all()
        user_id = self.request.user.id
        if 'VENDEDOR' in grupos:
            ids = user_id
        elif 'SUPERVISOR' in grupos:
            ids = SupervisorVendedor.objects.filter(user_id=user_id).values_list(
                'vendedor_id', flat=True)
        ventas = Venta.objects.filter(vendedor_id__in=ids)
        
        return {'ventas': ventas}

Independientemente de si usamos el sistema de usuario y contraseña, o si usamos JWT nuestras vistas quedan igual.

Conclusión

La implementación de la autenticación y autorización usando restframework es muy simple y no varía mucho del plain Django. Como pudimos ver en el código de las vistas solo hay que quitar el mixin de la autorización de la clase, e implementar la variable permission_classes para indicar los permisos y si queremos o no que el usuario esté autenticado.