Dobrą praktyką jest okresowe odnawianie tokenu uwierzytelniania przez klientów mobilnych. To oczywiście zależy od serwera.
Domyślna klasa TokenAuthentication nie obsługuje tego, jednak można ją rozszerzyć, aby uzyskać tę funkcjonalność.
Na przykład:
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
Wymagane jest również nadpisanie domyślnego widoku logowania do struktury odpoczynku, aby token był odświeżany po każdym logowaniu:
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()
I nie zapomnij zmodyfikować adresów URL:
urlpatterns += patterns(
'',
url(r'^users/login/?$', '<path_to_file>.obtain_expiring_auth_token'),
)
Jeśli ktoś jest zainteresowany tym rozwiązaniem, ale chce mieć token ważny przez określony czas to zostanie zastąpiony nowym tokenem, oto kompletne rozwiązanie (Django 1.6):
yourmodule / views.py:
yourmodule / urls.py:
twój projekt urls.py (w tablicy urlpatterns):
yourmodule / authentication.py:
W ustawieniach REST_FRAMEWORK dodaj ExpiringTokenAuthentication jako klasę uwierzytelniania zamiast TokenAuthentication:
źródło
'ObtainExpiringAuthToken' object has no attribute 'serializer_class'
gdy próbuję uzyskać dostęp do punktu końcowego interfejsu API. Nie wiem, czego mi brakuje.Próbowałem odpowiedzieć @odedfos, ale wystąpił błąd wprowadzający w błąd . Oto ta sama odpowiedź, ustalona i z odpowiednim importem.
views.py
authentication.py
źródło
Pomyślałem, że udzielę odpowiedzi w Django 2.0 używając DRY. Ktoś już to dla nas zbudował, Google Django OAuth ToolKit. Dostępne z pip,
pip install django-oauth-toolkit
. Instrukcje dotyczące dodawania tokenów ViewSets z routerami: https://django-oauth-toolkit.readthedocs.io/en/latest/rest-framework/getting_started.html . Jest podobny do oficjalnego samouczka.Zasadniczo OAuth1.0 było bardziej wczorajszym zabezpieczeniem, którym jest TokenAuthentication. Aby uzyskać wymyślne wygasające tokeny, w dzisiejszych czasach popularna jest OAuth2.0. Otrzymasz AccessToken, RefreshToken i zmienną zakresu, aby dostosować uprawnienia. Otrzymasz takie kredyty:
źródło
Zapytał autor
Ale wszystkie odpowiedzi piszą o tym, jak automatycznie zmienić token.
Myślę, że okresowe zmienianie tokena po tokenie jest bez znaczenia. Reszta frameworka tworzy token, który ma 40 znaków, jeśli atakujący testuje 1000 tokenów na sekundę,
16**40/1000/3600/24/365=4.6*10^7
zdobycie tokena zajmuje lata. Nie powinieneś się martwić, że atakujący przetestuje twój żeton jeden po drugim. Nawet jeśli zmieniłeś swój token, prawdopodobieństwo odgadnięcia, że token jest takie samo.Jeśli obawiasz się, że może napastnicy mogą dostać twój token, więc zmieniasz go okresowo, to po tym, jak atakujący otrzyma token, może również zmienić twój token, a prawdziwy użytkownik jest wyrzucany.
To, co naprawdę powinieneś zrobić, to uniemożliwić atakującemu uzyskanie tokena użytkownika, użyj https .
Nawiasem mówiąc, mówię tylko, że zmiana tokena po tokenie jest bez znaczenia, zmiana tokena według nazwy użytkownika i hasła jest czasami znacząca. Może token jest używany w jakimś środowisku http (zawsze należy unikać tego typu sytuacji) lub w jakiejś trzeciej firmie (w tym przypadku należy stworzyć inny rodzaj tokena, użyć oauth2) i gdy użytkownik robi coś niebezpiecznego, jak np. Zmiana wiążąc skrzynkę pocztową lub usuń konto, powinieneś upewnić się, że nie będziesz już używać tokena pochodzenia, ponieważ mógł zostać ujawniony przez atakującego za pomocą narzędzi sniffer lub tcpdump.
źródło
Możesz wykorzystać http://getblimp.github.io/django-rest-framework-jwt
Ta biblioteka może generować token z datą wygaśnięcia
Aby zrozumieć różnicę między domyślnym tokenem DRF a tokenem dostarczonym przez DRF, należy spojrzeć na:
Jak sprawić, by Django REST JWT Authentication skalowało się z wieloma serwerami WWW?
źródło
Jeśli zauważysz, że token jest jak plik cookie sesji, możesz trzymać się domyślnego czasu życia plików cookie sesji w Django: https://docs.djangoproject.com/en/1.4/ref/settings/#session-cookie-age .
Nie wiem, czy Django Rest Framework obsługuje to automatycznie, ale zawsze możesz napisać krótki skrypt, który odfiltruje nieaktualne i oznaczy je jako wygasłe.
źródło
Pomyślałem, że dodam moje, ponieważ było to dla mnie pomocne. Zwykle korzystam z metody JWT, ale czasami coś takiego jest lepsze. Zaktualizowałem zaakceptowaną odpowiedź dla django 2.1 z poprawnymi importami.
authentication.py
views.py
źródło
aby nadal dodawać do odpowiedzi @odedfos, myślę, że nastąpiły pewne zmiany w składni, więc kod ExpiringTokenAuthentication wymaga dostosowania:
Nie zapomnij również dodać go do DEFAULT_AUTHENTICATION_CLASSES zamiast rest_framework.authentication.TokenAuthentication
źródło