Es una buena práctica que los clientes móviles renueven periódicamente su token de autenticación. Por supuesto, esto depende del servidor para hacer cumplir.
La clase TokenAuthentication predeterminada no admite esto, sin embargo, puede ampliarla 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 es necesario anular la vista de inicio de sesión del marco de descanso predeterminado, de modo que el token se actualice cada vez que se realiza un inicio de 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 olvide modificar las URL:
urlpatterns += patterns(
'',
url(r'^users/login/?$', '<path_to_file>.obtain_expiring_auth_token'),
)
Si alguien está interesado en esa solución pero quiere tener un token que sea válido por un tiempo determinado, entonces es reemplazado por un nuevo token, aquí está la solución completa (Django 1.6):
yourmodule / views.py:
yourmodule / urls.py:
su proyecto urls.py (en la matriz urlpatterns):
yourmodule / authentication.py:
En la configuración de REST_FRAMEWORK, agregue ExpiringTokenAuthentication como una clase de autenticación en lugar de TokenAuthentication:
fuente
'ObtainExpiringAuthToken' object has no attribute 'serializer_class'
cuando intento acceder al punto final de la API. No estoy seguro de lo que me estoy perdiendo.Probé la respuesta de @odedfos pero tuve un error engañoso . Aquí está la misma respuesta, arreglada y con las importaciones adecuadas.
views.py
authentication.py
fuente
Pensé que daría una respuesta de Django 2.0 usando DRY. Alguien ya creó esto para nosotros, Google Django OAuth ToolKit. Disponible con PIP,
pip install django-oauth-toolkit
. Instrucciones sobre cómo agregar los ViewSets de token con enrutadores: https://django-oauth-toolkit.readthedocs.io/en/latest/rest-framework/getting_started.html . Es similar al tutorial oficial.Entonces, básicamente, OAuth1.0 era más la seguridad de ayer, que es lo que es TokenAuthentication. Para obtener tokens elegantes con vencimiento, OAuth2.0 está de moda en estos días. Obtiene un AccessToken, RefreshToken y una variable de alcance para ajustar los permisos. Terminas con credenciales como esta:
fuente
El autor preguntó
Pero todas las respuestas están escribiendo sobre cómo cambiar automáticamente el token.
Creo que cambiar token periódicamente por token no tiene sentido. El resto del marco crea un token que tiene 40 caracteres, si el atacante prueba 1000 token por segundo, se necesitan
16**40/1000/3600/24/365=4.6*10^7
años para obtener el token. No debe preocuparse de que el atacante pruebe su token uno por uno. Incluso si cambió su ficha, la probabilidad de adivinar su ficha es la misma.Si le preocupa que tal vez los atacantes puedan obtener su token, entonces lo cambia periódicamente, después de que el atacante obtenga el token, también puede cambiar su token, entonces el usuario real es expulsado.
Lo que realmente debe hacer es evitar que el atacante obtenga el token de su usuario, use https .
Por cierto, solo digo que cambiar token por token no tiene sentido, cambiar token por nombre de usuario y contraseña a veces es significativo. Tal vez el token se use en algún entorno http (siempre debe evitar este tipo de situación) o en algún tercero (en este caso, debe crear un tipo diferente de token, use oauth2) y cuando el usuario esté haciendo algo peligroso como cambiar vincular el buzón o eliminar la cuenta, debe asegurarse de que no volverá a usar el token de origen porque puede haber sido revelado por el atacante usando herramientas sniffer o tcpdump.
fuente
Puede aprovechar http://getblimp.github.io/django-rest-framework-jwt
Esta biblioteca puede generar tokens que tienen una fecha de vencimiento.
Para comprender la diferencia entre el token predeterminado de DRF y el token proporcionado por DRF, eche un vistazo a:
¿Cómo hacer que Django REST JWT Authentication escale con múltiples servidores web?
fuente
Si nota que un token es como una cookie de sesión, puede ceñirse a la duración predeterminada 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 puede escribir un script corto que filtre los desactualizados y los marque como vencidos.
fuente
Solo pensé en agregar el mío, ya que esto fue útil para mí. Yo suelo usar el método JWT, pero a veces algo como esto es mejor. Actualicé la respuesta aceptada para django 2.1 con las importaciones adecuadas.
autenticación.py
views.py
fuente
solo para seguir agregando a la respuesta de @odedfos, creo que ha habido algunos cambios en la sintaxis, por lo que el código de ExpiringTokenAuthentication necesita algunos ajustes:
Además, no olvide agregarlo a DEFAULT_AUTHENTICATION_CLASSES en lugar de rest_framework.authentication.TokenAuthentication
fuente