mirror of
https://github.com/Tivix/django-rest-auth.git
synced 2025-07-09 15:42:26 +03:00
Adds view for refreshing tokens with cookies (#173)
This commit is contained in:
parent
5301f1e437
commit
441b2e9962
|
@ -1,7 +1,37 @@
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from rest_framework_simplejwt.authentication import JWTAuthentication
|
from django.utils import timezone
|
||||||
from rest_framework import exceptions
|
from rest_framework import exceptions
|
||||||
from rest_framework.authentication import CSRFCheck
|
from rest_framework.authentication import CSRFCheck
|
||||||
|
from rest_framework_simplejwt.authentication import JWTAuthentication
|
||||||
|
|
||||||
|
|
||||||
|
def get_refresh_view():
|
||||||
|
""" Returns a Token Refresh CBV without a circular import """
|
||||||
|
from rest_framework_simplejwt.settings import api_settings as jwt_settings
|
||||||
|
from rest_framework_simplejwt.views import TokenRefreshView
|
||||||
|
|
||||||
|
class RefreshViewWithCookieSupport(TokenRefreshView):
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
response = super().post(request, *args, **kwargs)
|
||||||
|
cookie_name = getattr(settings, 'JWT_AUTH_COOKIE', None)
|
||||||
|
if cookie_name and response.status_code == 200 and 'access' in response.data:
|
||||||
|
cookie_secure = getattr(settings, 'JWT_AUTH_SECURE', False)
|
||||||
|
cookie_httponly = getattr(settings, 'JWT_AUTH_HTTPONLY', True)
|
||||||
|
cookie_samesite = getattr(settings, 'JWT_AUTH_SAMESITE', 'Lax')
|
||||||
|
token_expiration = (timezone.now() + jwt_settings.ACCESS_TOKEN_LIFETIME)
|
||||||
|
response.set_cookie(
|
||||||
|
cookie_name,
|
||||||
|
response.data['access'],
|
||||||
|
expires=token_expiration,
|
||||||
|
secure=cookie_secure,
|
||||||
|
httponly=cookie_httponly,
|
||||||
|
samesite=cookie_samesite,
|
||||||
|
)
|
||||||
|
|
||||||
|
response.data['access_token_expiration'] = token_expiration
|
||||||
|
return response
|
||||||
|
return RefreshViewWithCookieSupport
|
||||||
|
|
||||||
|
|
||||||
class JWTCookieAuthentication(JWTAuthentication):
|
class JWTCookieAuthentication(JWTAuthentication):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -913,3 +913,23 @@ class APIBasicTests(TestsMixin, TestCase):
|
||||||
self.assertIn('xxx', resp.cookies.keys())
|
self.assertIn('xxx', resp.cookies.keys())
|
||||||
self.assertIn('refresh-xxx', resp.cookies.keys())
|
self.assertIn('refresh-xxx', resp.cookies.keys())
|
||||||
self.assertEqual(resp.cookies.get('refresh-xxx').get('path'), '/foo/bar')
|
self.assertEqual(resp.cookies.get('refresh-xxx').get('path'), '/foo/bar')
|
||||||
|
|
||||||
|
@override_settings(JWT_AUTH_RETURN_EXPIRATION=True)
|
||||||
|
@override_settings(REST_USE_JWT=True)
|
||||||
|
@override_settings(JWT_AUTH_COOKIE='xxx')
|
||||||
|
@override_settings(JWT_AUTH_REFRESH_COOKIE='refresh-xxx')
|
||||||
|
def test_custom_token_refresh_view(self):
|
||||||
|
payload = {
|
||||||
|
"username": self.USERNAME,
|
||||||
|
"password": self.PASS
|
||||||
|
}
|
||||||
|
|
||||||
|
get_user_model().objects.create_user(self.USERNAME, '', self.PASS)
|
||||||
|
resp = self.post(self.login_url, data=payload, status_code=200)
|
||||||
|
refresh = resp.data.get('refresh_token')
|
||||||
|
refresh_resp = self.post(
|
||||||
|
reverse('token_refresh'),
|
||||||
|
data=dict(refresh=refresh),
|
||||||
|
status_code=200
|
||||||
|
)
|
||||||
|
self.assertIn('xxx', refresh_resp.cookies)
|
||||||
|
|
|
@ -1,6 +1,16 @@
|
||||||
from allauth.socialaccount.providers.facebook.views import \
|
from allauth.socialaccount.providers.facebook.views import \
|
||||||
FacebookOAuth2Adapter
|
FacebookOAuth2Adapter
|
||||||
from allauth.socialaccount.providers.twitter.views import TwitterOAuthAdapter
|
from allauth.socialaccount.providers.twitter.views import TwitterOAuthAdapter
|
||||||
|
from django.conf.urls import include, url
|
||||||
|
from django.views.decorators.csrf import ensure_csrf_cookie
|
||||||
|
from django.views.generic import TemplateView
|
||||||
|
from rest_framework import permissions
|
||||||
|
from rest_framework.decorators import api_view
|
||||||
|
from rest_framework.response import Response
|
||||||
|
from rest_framework.views import APIView
|
||||||
|
from rest_framework_simplejwt.views import TokenVerifyView
|
||||||
|
|
||||||
|
from dj_rest_auth.jwt_auth import get_refresh_view
|
||||||
from dj_rest_auth.registration.views import (SocialAccountDisconnectView,
|
from dj_rest_auth.registration.views import (SocialAccountDisconnectView,
|
||||||
SocialAccountListView,
|
SocialAccountListView,
|
||||||
SocialConnectView,
|
SocialConnectView,
|
||||||
|
@ -8,14 +18,6 @@ from dj_rest_auth.registration.views import (SocialAccountDisconnectView,
|
||||||
from dj_rest_auth.social_serializers import (TwitterConnectSerializer,
|
from dj_rest_auth.social_serializers import (TwitterConnectSerializer,
|
||||||
TwitterLoginSerializer)
|
TwitterLoginSerializer)
|
||||||
from dj_rest_auth.urls import urlpatterns
|
from dj_rest_auth.urls import urlpatterns
|
||||||
from django.conf.urls import include, url
|
|
||||||
from django.views.generic import TemplateView
|
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
from django.views.decorators.csrf import ensure_csrf_cookie
|
|
||||||
from rest_framework import permissions
|
|
||||||
from rest_framework.decorators import api_view
|
|
||||||
from rest_framework.response import Response
|
|
||||||
from rest_framework.views import APIView
|
|
||||||
|
|
||||||
from . import django_urls
|
from . import django_urls
|
||||||
|
|
||||||
|
@ -64,6 +66,7 @@ def twitter_login_view(request):
|
||||||
class TwitterLoginNoAdapter(SocialLoginView):
|
class TwitterLoginNoAdapter(SocialLoginView):
|
||||||
serializer_class = TwitterLoginSerializer
|
serializer_class = TwitterLoginSerializer
|
||||||
|
|
||||||
|
|
||||||
@ensure_csrf_cookie
|
@ensure_csrf_cookie
|
||||||
@api_view(['GET'])
|
@api_view(['GET'])
|
||||||
def get_csrf_cookie(request):
|
def get_csrf_cookie(request):
|
||||||
|
@ -89,4 +92,6 @@ urlpatterns += [
|
||||||
name='social_account_disconnect'),
|
name='social_account_disconnect'),
|
||||||
url(r'^accounts/', include('allauth.socialaccount.urls')),
|
url(r'^accounts/', include('allauth.socialaccount.urls')),
|
||||||
url(r'^getcsrf/', get_csrf_cookie, name='getcsrf'),
|
url(r'^getcsrf/', get_csrf_cookie, name='getcsrf'),
|
||||||
|
url('^token/verify/', TokenVerifyView.as_view(), name='token_verify'),
|
||||||
|
url('^token/refresh/', get_refresh_view().as_view(), name='token_refresh'),
|
||||||
]
|
]
|
|
@ -1,8 +1,9 @@
|
||||||
|
from django.conf import settings
|
||||||
|
from django.urls import path
|
||||||
|
|
||||||
from dj_rest_auth.views import (LoginView, LogoutView, PasswordChangeView,
|
from dj_rest_auth.views import (LoginView, LogoutView, PasswordChangeView,
|
||||||
PasswordResetConfirmView, PasswordResetView,
|
PasswordResetConfirmView, PasswordResetView,
|
||||||
UserDetailsView)
|
UserDetailsView)
|
||||||
from django.urls import path
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
# URLs that do not require a session or valid token
|
# URLs that do not require a session or valid token
|
||||||
|
@ -16,11 +17,11 @@ urlpatterns = [
|
||||||
]
|
]
|
||||||
|
|
||||||
if getattr(settings, 'REST_USE_JWT', False):
|
if getattr(settings, 'REST_USE_JWT', False):
|
||||||
from rest_framework_simplejwt.views import (
|
from rest_framework_simplejwt.views import TokenVerifyView
|
||||||
TokenRefreshView, TokenVerifyView,
|
|
||||||
)
|
from dj_rest_auth.jwt_auth import get_refresh_view
|
||||||
|
|
||||||
urlpatterns += [
|
urlpatterns += [
|
||||||
path('token/verify/', TokenVerifyView.as_view(), name='token_verify'),
|
path('token/verify/', TokenVerifyView.as_view(), name='token_verify'),
|
||||||
path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
|
path('token/refresh/', get_refresh_view().as_view(), name='token_refresh'),
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in New Issue
Block a user