visual studio por example ejemplo crear basada autenticacion django rest restful-authentication django-rest-framework

django - studio - web api ejemplo



Autenticación Token para API RESTful: ¿debería cambiarse el token periódicamente? (6)

Estoy construyendo una API RESTful con Django y django-rest-framework .

Como mecanismo de autenticación elegimos "Autenticación Token" y ya lo he implementado siguiendo la documentación de Django-REST-Framework, la pregunta es si la aplicación debe renovar / cambiar el Token periódicamente y, en caso afirmativo, ¿cómo? ¿Debería ser la aplicación móvil la que requiere la renovación del token o la aplicación web debería hacerlo de manera autónoma?

cual es la mejor practica?

¿Alguien aquí experimentó con Django REST Framework y podría sugerir una solución técnica?

(la última pregunta tiene una prioridad más baja)


Intenté la respuesta de @odedfos pero tuve un error engañoso . Aquí está la misma respuesta, arreglada y con importaciones apropiadas.

views.py

from django.utils import timezone from rest_framework import status from rest_framework.response import Response from rest_framework.authtoken.models import Token from rest_framework.authtoken.views import ObtainAuthToken class ObtainExpiringAuthToken(ObtainAuthToken): def post(self, request): serializer = self.serializer_class(data=request.DATA) if serializer.is_valid(): token, created = Token.objects.get_or_create(user=serializer.object[''user'']) if not created: # update the created time of the token to keep it valid token.created = datetime.datetime.utcnow().replace(tzinfo=utc) token.save() return Response({''token'': token.key}) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

authentication.py

from datetime import timedelta from django.conf import settings from django.utils import timezone from rest_framework.authentication import TokenAuthentication from rest_framework import exceptions EXPIRE_HOURS = getattr(settings, ''REST_FRAMEWORK_TOKEN_EXPIRE_HOURS'', 24) class ExpiringTokenAuthentication(TokenAuthentication): def authenticate_credentials(self, key): try: token = self.model.objects.get(key=key) except self.model.DoesNotExist: raise exceptions.AuthenticationFailed(''Invalid token'') if not token.user.is_active: raise exceptions.AuthenticationFailed(''User inactive or deleted'') if token.created < timezone.now() - timedelta(hours=EXPIRE_HOURS): raise exceptions.AuthenticationFailed(''Token has expired'') return (token.user, token)


Pensé que daría una respuesta Django 2.0 con DRY. Alguien ya lo construyó para nosotros, google Django OAuth ToolKit. Disponible con pip, pip install django-oauth-toolkit . Instrucciones para agregar el token ViewSets con enrutadores: https://django-oauth-toolkit.readthedocs.io/en/latest/rest-framework/getting_started.html . Es similar al tutorial oficial.

Así que, básicamente, OAuth1.0 era más seguridad de ayer, que es lo que es TokenAuthentication. Para obtener tokens que expiran, OAuth2.0 está de moda en estos días. Obtiene una AccessToken, RefreshToken y una variable de ámbito para ajustar los permisos. Terminas con creds como este:

{ "access_token": "<your_access_token>", "token_type": "Bearer", "expires_in": 3600, "refresh_token": "<your_refresh_token>", "scope": "read" }



Si a alguien le interesa esa solución pero quiere tener un token que es válido durante un tiempo determinado y luego es reemplazado por un nuevo token, aquí está la solución completa (Django 1.6):

yourmodule / views.py:

import datetime from django.utils.timezone import utc from rest_framework.authtoken.views import ObtainAuthToken from rest_framework.authtoken.models import Token from django.http import HttpResponse import json class ObtainExpiringAuthToken(ObtainAuthToken): def post(self, request): serializer = self.serializer_class(data=request.DATA) if serializer.is_valid(): token, created = Token.objects.get_or_create(user=serializer.object[''user'']) utc_now = datetime.datetime.utcnow() if not created and token.created < utc_now - datetime.timedelta(hours=24): token.delete() token = Token.objects.create(user=serializer.object[''user'']) token.created = datetime.datetime.utcnow() token.save() #return Response({''token'': token.key}) response_data = {''token'': token.key} return HttpResponse(json.dumps(response_data), content_type="application/json") return HttpResponse(serializer.errors, status=status.HTTP_400_BAD_REQUEST) obtain_expiring_auth_token = ObtainExpiringAuthToken.as_view()

yourmodule / urls.py:

from django.conf.urls import patterns, include, url from weights import views urlpatterns = patterns('''', url(r''^token/'', ''yourmodule.views.obtain_expiring_auth_token'') )

su proyecto urls.py (en la matriz urlpatterns):

url(r''^'', include(''yourmodule.urls'')),

yourmodule / authentication.py:

import datetime from django.utils.timezone import utc from rest_framework.authentication import TokenAuthentication from rest_framework import exceptions class ExpiringTokenAuthentication(TokenAuthentication): def authenticate_credentials(self, key): try: token = self.model.objects.get(key=key) except self.model.DoesNotExist: raise exceptions.AuthenticationFailed(''Invalid token'') if not token.user.is_active: raise exceptions.AuthenticationFailed(''User inactive or deleted'') utc_now = datetime.datetime.utcnow() if token.created < utc_now - datetime.timedelta(hours=24): raise exceptions.AuthenticationFailed(''Token has expired'') return (token.user, token)

En su configuración REST_FRAMEWORK, agregue ExpiringTokenAuthentication como una clase de autenticación en lugar de TokenAuthentication:

REST_FRAMEWORK = { ''DEFAULT_AUTHENTICATION_CLASSES'': ( ''rest_framework.authentication.SessionAuthentication'', #''rest_framework.authentication.TokenAuthentication'', ''yourmodule.authentication.ExpiringTokenAuthentication'', ), }


Si observa que un token es como una cookie de sesión, puede mantener el tiempo de vida predeterminado de las cookies de sesión en Django: https://docs.djangoproject.com/en/1.4/ref/settings/#session-cookie-age .

No sé si Django Rest Framework maneja eso automáticamente, pero siempre puedes escribir un pequeño script que filtra los obsoletos y los marca como caducados.


Es una buena práctica que los clientes móviles renueven periódicamente su token de autenticación. Esto, por supuesto, depende del servidor para hacer cumplir.

La clase predeterminada TokenAuthentication no es compatible con esto, sin embargo, puede ampliarlo para lograr esta funcionalidad.

Por ejemplo:

from rest_framework.authentication import TokenAuthentication, get_authorization_header from rest_framework.exceptions import AuthenticationFailed class ExpiringTokenAuthentication(TokenAuthentication): def authenticate_credentials(self, key): try: token = self.model.objects.get(key=key) except self.model.DoesNotExist: raise exceptions.AuthenticationFailed(''Invalid token'') if not token.user.is_active: raise exceptions.AuthenticationFailed(''User inactive or deleted'') # This is required for the time comparison utc_now = datetime.utcnow() utc_now = utc_now.replace(tzinfo=pytz.utc) if token.created < utc_now - timedelta(hours=24): raise exceptions.AuthenticationFailed(''Token has expired'') return token.user, token

También se requiere que se sobrescriba la vista de inicio de sesión del marco de trabajo predeterminado, de modo que el token se actualice cada vez que se inicie sesión:

class ObtainExpiringAuthToken(ObtainAuthToken): def post(self, request): serializer = self.serializer_class(data=request.data) if serializer.is_valid(): token, created = Token.objects.get_or_create(user=serializer.validated_data[''user'']) if not created: # update the created time of the token to keep it valid token.created = datetime.datetime.utcnow() token.save() return Response({''token'': token.key}) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) obtain_expiring_auth_token = ObtainExpiringAuthToken.as_view()

Y no te olvides de modificar las URL:

urlpatterns += patterns( '''', url(r''^users/login/?$'', ''<path_to_file>.obtain_expiring_auth_token''), )