Permisos Avanzados10 temas

Permisos Avanzados

DRF ofrece un sistema de permisos flexible y componible. Desde roles simples hasta lógica condicional compleja, se puede controlar exactamente quién hace qué en la API.

Custom Permission básica

from rest_framework.permissions import BasePermission

class IsStaff(BasePermission):
    """Solo usuarios staff pueden acceder."""
    def has_permission(self, request, view):
        return request.user and request.user.is_staff

Permission a nivel de objeto

Controla el acceso según el dueño del recurso:

class IsOwner(BasePermission):
    """
    - GET, HEAD, OPTIONS: cualquiera autenticado puede leer
    - PUT, PATCH, DELETE: solo el owner puede modificar
    """
    def has_object_permission(self, request, view, obj):
        if request.method in ('GET', 'HEAD', 'OPTIONS'):
            return True
        return obj.author == request.user

Nota: has_object_permission se ejecuta DESPUÉS de has_permission. Si esta última falla, nunca llega al nivel de objeto. Además, solo se invoca si la vista obtiene el objeto explícitamente (vistas genéricas lo hacen automáticamente).

Permisos dinámicos por acción

Diferentes acciones del ViewSet pueden tener diferentes permisos:

from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import IsAuthenticated, IsAdminUser
from rest_framework.decorators import action

class PostViewSet(ModelViewSet):
    def get_permissions(self):
        if self.action == 'create':
            return [IsAuthenticated()]
        elif self.action in ('destroy', 'close'):
            return [IsAdminUser()]
        return [IsAuthenticated()]

    @action(detail=True, methods=['post'])
    def close(self, request, pk=None):
        """Cerrar un post — solo admins."""
        post = self.get_object()
        post.status = 'closed'
        post.save()
        return Response({'status': 'closed'})

Composición de permisos

Combinar permisos con AND / OR:

from rest_framework.permissions import OR

# OR: cualquiera que pase
class PostViewSet(ModelViewSet):
    permission_classes = [OR(IsAdminUser, IsOwner)]

    # AND: todos deben pasar (es el default, solo listarlos)
class PostViewSet(ModelViewSet):
    permission_classes = [IsAuthenticated, IsStaff]

Resumen de patrones

Patrón Implementación Caso de uso
Rol simple BasePermission.has_permission() “Solo admins”
Object-level BasePermission.has_object_permission() “Solo el dueño puede editar”
Dinámico por acción ViewSet.get_permissions() Diferentes permisos por endpoint
Composición AND(), OR() Condiciones complejas
Grupos user.groups.filter(...) Integración con sistema de grupos de Django

Diferencia clave: has_permission controla el acceso al endpoint (nivel vista). has_object_permission controla el acceso al recurso específico (nivel objeto). Usar ambas cuando se necesiten las dos capas.

Recursos

DRF Docs: Permissions