Permisos y autentificación con Django REST Framework
En el anterior post - Introducción a Django REST Framework - creamos una simple API para crear, modificar, eliminar y listar encuestas. Hoy continuaremos con el mismo proyecto para ver como utilizar permisos y autentificarnos a la hora de conectarnos a la API.
La autentificación más básica
Para poder autentificarnos, necesitaremos un usuario, por lo que vamos a modificar nuestro modelo de datos (dado que el proyecto es tan simple que no estamos usando south, bastará con eliminar la base de datos db.sqlite3 para luego poder sincronizarla de nuevo -sincdb- con el nuevo modelo.Modificamos el usuario (owner) en survey/models.py
from django.db import modelsclass Survey(models.Model): owner = models.ForeignKey(‘auth.User’, related_name=’surveys’) title = models.CharField(max_length=50) question = models.CharField(max_length=300) active = models.BooleanField(default=True) created = models.DateTimeField(auto_now_add=True, auto_now=False) updated = models.DateTimeField(auto_now_add=False, auto_now=True)
Incorporamos el usuario al serializer
Tenemos que crear un dato miembro en el serializer para nuestro usuario, así que modificamos api/serialiers.py:from rest_framework import serializersEs importante que mantengamos owner como uno de los campos a serializar.from survey.models import Survey, SurveyVotes
class SurveySerializer(serializers.ModelSerializer): owner = serializers.Field(‘owner.username’)
class Meta: model = Survey fields = (‘title’, ‘description’, ‘owner’, ‘recipients’, ‘options’, ‘active’)
Creamos los permisos de uso
En nuestro ejemplo, vamos a considerar los siguientes usos: 1. Cuaquier usuario no autentificado, podrá leer las encuestras 2. Para crear una encuesta, será necesario estar autentificado 3. Para editar o borrar una encuesta, será necesario ser el propietario de la misma.Con este objetivo, creamos el fichero api/permissions.py y añadimos el siguiente contenido:
from rest_framework.permissions import BasePermission, SAFE_METHODS #SAFE_METHODS are get, post and head¿Qué hemos hecho? Hemos creado una clase que hereda de BasePermission, donde hemos implementado método has_object_permission(), que devuelve True si el método se considera como seguro (permisos de lectura: GET, HEAD y OPTIONS). En caso contrario, comprueba si el usuario es el propietario del objeto, y si se da el caso afirmativo, también da el permiso.class IsOwnerOrReadOnly(BasePermission): def has_object_permission(self, request, view, obj): if request.method in SAFE_METHODS: return True return obj.owner == request.user
Esta clase se deberá usar en las vistas para realizar la comprobación deseada.
Incorporamos la autentificación en las vistas
from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView from survey.models import Survey from .permissions import IsOwnerOrReadOnly from .serializers import SurveySerializerComo vemos, dotamos al SurveyMixin del que heredan nuestras vistas de un dato miembro permission_classes, donde debemos incluir una tupla con las clases de permisos que requieren nuestras vistas.class SurveyMixin(object): queryset = Survey.objects.all() serializer_class = SurveySerializer permission_classes = (IsOwnerOrReadOnly,)
def pre_save(self, obj): obj.owner = self.request.user
class SurveyList(SurveyMixin, ListCreateAPIView): pass
class SurveyDetails(SurveyMixin, RetrieveUpdateDestroyAPIView): pass
Es interesante ver como creamos el método pre_save() para que incorpore al usuario como propietario, lo que permitirá que IsOwnerOrReadOnly.has_object_permission() devuelva True cuando se crea una nueva encuesta.
Primeras pruebas
Hecho esto, podremos crear nuestra base de datos(entornoSurvey)$ ./manage.py syncdby empezar a probar nuestros cambios con curl, PostMan, o lo que usemos.
Como detalle, indicar que para pasar un usuario y password en curl se utiliza la opción -u user:pswd, mientras que PostMan tiene una pestaña en la parte superior para proporcionar usuario y password (Basic Auth).
Por otro lado, si queremos probar varios usuarios para ver que pasa cuando intentamos acceder a una encuesta de la que no tenemos propiedad, podemos usar el comando:
(entornoSurvey)$ ./manage.py createsuperuser
Utilizando el front-end de Django REST Framework: Login
Como ya habrás visto, si te conectas mediante el navegador a la API, en lugar de obtener el resultado en JSON, lo que obtienes es una vista de información sobre la API, que te dice qué métodos puedes llamar concretamente para la URL que has introducido, e incluso te proporciona un formulario para realizar las peticiones. Algo del estilo a lo que vemos en la imagen:
Si pruebas con la API que hemos desarrollado actualmente, por ejemplo, en http://127.0.0.1:8000/api/surveys/ (se abre en una pestaña nueva), deberías hechar de menos el login o usuario a la derecha de la barra superior. También deberías ver, si intentas crear una nueva survey desde el frontend, que no te dejará. Tienes que estar logueado.
Para solucionar esto, vamos a añadir URLs para que el front-end nos permita loguearnos, y además vamos a crear también la API para ver usuarios y sus encuestas.
Añadimos el UserSerializer vinculado a las surveys
Modificamos nuestro archivo api/serializers.py que debería quedar así:from django.contrib.auth.models import User from rest_framework import serializers from survey.models import Surveyclass SurveySerializer(serializers.ModelSerializer): owner = serializers.Field(source=’owner.username’)
class Meta: model = Survey fields = (‘title’, ‘description’,’owner’, ‘recipients’, ‘options’, ‘active’)
class UserSerializer(serializers.ModelSerializer): #surveys es una relacion inversa en User, por lo que la declaramos explícitamente surveys = serializers.PrimaryKeyRelatedField(many=True)
class Meta: model = User fields = (‘id’, ‘username’, ‘surveys’)
Añadimos las vistas de User
En nuestro archivo api/views.py añadimos:from rest_framework.generics import ListAPIView, ListCreateAPIView, RetrieveAPIView, RetrieveUpdateDestroyAPIView from django.contrib.auth.models import User from .serializers import SurveySerializer, UserSerializerComo se podía intuir cuando hemos definido en Survey el owner como ForeignKey del modelo User de Django, vamos a utilizar directamente dicho modelo, por lo que no tocaremos el fichero models.py.class UserList(ListAPIView): queryset = User.objects.all() serializer_class = UserSerializer
class UserDetail(RetrieveAPIView): queryset = User.objects.all() serializer_class = UserSerializer
Acceso URL a nuestra API de users
Editamos el archivo api/urls.py para incluir las siguientes urls:url(r’^users/$’, views.UserList.as_view(), name=’user_list’), url(r’^users/(?P[0-9]+)$’, views.UserDetail.as_view(), name=’user_details’),
Acceso URL para loguearnos
Editamos el archivo de rutas principal survey_proj/urls.py para incluir las urls de Django REST framework:url(r’^api-auth/’, include(‘rest_framework.urls‘, namespace=’rest_framework‘)),A partir de este momento, debería aparecernos a la derecha de la barra superior un enlace para loguearnos y desloguearnos, con lo que podremos usar el frontend para acceder a la api de forma autentificada, y por supuesto, ahora dipondremos también de una API para obtener una lista de usuarios, o información de un usuario concreto.
¿Te ha gustado este artículo? No te cortes, déjame un comentario y ayúdame a compartirlo 😉
Comentarios
Para comentar necesitas una cuenta de GitHub.