version 0.0.12: updated JWT views
This commit is contained in:
parent
d5a14ef8c2
commit
663c003119
|
|
@ -19,12 +19,16 @@ from account.models import User
|
|||
from authorization.models import Application
|
||||
from authorization.serializers import common as serializers
|
||||
from utils import exceptions as utils_exceptions
|
||||
from utils.views import JWTViewMixin
|
||||
from utils.views import (JWTGenericViewMixin,
|
||||
JWTCreateAPIView,
|
||||
JWTDestroyAPIView,
|
||||
JWTUpdateAPIView,
|
||||
JWTRetrieveAPIView)
|
||||
|
||||
|
||||
# Mixins
|
||||
# JWTAuthView mixin
|
||||
class JWTAuthViewMixin(JWTViewMixin):
|
||||
class JWTAuthViewMixin(JWTCreateAPIView):
|
||||
"""Mixin for authentication views"""
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
|
|
@ -98,7 +102,7 @@ class OAuth2ViewMixin(CsrfExemptMixin, OAuthLibMixin, BaseOAuth2ViewMixin):
|
|||
|
||||
|
||||
# Sign in via Facebook
|
||||
class OAuth2SignUpView(OAuth2ViewMixin, JWTAuthViewMixin):
|
||||
class OAuth2SignUpView(OAuth2ViewMixin, JWTCreateAPIView):
|
||||
"""
|
||||
Implements an endpoint to convert a provider token to an access token
|
||||
|
||||
|
|
@ -176,7 +180,7 @@ class OAuth2SignUpView(OAuth2ViewMixin, JWTAuthViewMixin):
|
|||
|
||||
# JWT
|
||||
# Sign in via username and password
|
||||
class SignUpView(JWTAuthViewMixin):
|
||||
class SignUpView(JWTCreateAPIView):
|
||||
"""View for classic signup"""
|
||||
permission_classes = (permissions.AllowAny, )
|
||||
serializer_class = serializers.SignupSerializer
|
||||
|
|
@ -207,18 +211,37 @@ class SignUpView(JWTAuthViewMixin):
|
|||
|
||||
|
||||
# Login by username|email + password
|
||||
class LoginByUsernameOrEmailView(JWTAuthViewMixin):
|
||||
class LoginByUsernameOrEmailView(JWTCreateAPIView):
|
||||
"""Login by email and password"""
|
||||
permission_classes = (permissions.AllowAny,)
|
||||
serializer_class = serializers.LoginByUsernameOrEmailSerializer
|
||||
|
||||
|
||||
# Refresh access_token
|
||||
class RefreshTokenView(JWTAuthViewMixin):
|
||||
class RefreshTokenView(JWTGenericViewMixin):
|
||||
"""Refresh access_token"""
|
||||
permission_classes = (permissions.IsAuthenticated,)
|
||||
serializer_class = serializers.RefreshTokenSerializer
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
_locale = request.COOKIES.get('locale')
|
||||
try:
|
||||
locale = self._check_locale(locale=_locale)
|
||||
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
response = Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||
access_token, refresh_token = self._get_tokens_from_cookies(request)
|
||||
except utils_exceptions.LocaleNotExisted:
|
||||
raise utils_exceptions.LocaleNotExisted(locale=_locale)
|
||||
else:
|
||||
return self._put_cookies_in_response(
|
||||
cookies=self._put_data_in_cookies(locale=locale,
|
||||
access_token=access_token,
|
||||
refresh_token=refresh_token),
|
||||
response=response)
|
||||
|
||||
|
||||
# Logout
|
||||
class LogoutView(generics.CreateAPIView):
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
from rest_framework import generics, permissions
|
||||
from news.models import News
|
||||
from news.serializers import common as serializers
|
||||
from utils.views import JWTViewMixin
|
||||
from utils.views import JWTGenericViewMixin
|
||||
|
||||
|
||||
class NewsList(JWTViewMixin, generics.ListAPIView):
|
||||
class NewsList(generics.ListAPIView):
|
||||
"""News list view."""
|
||||
queryset = News.objects.all()
|
||||
permission_classes = (permissions.AllowAny, )
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ from rest_framework import generics
|
|||
from translation import models
|
||||
from translation import serializers
|
||||
from rest_framework import permissions
|
||||
from utils.views import JWTViewMixin
|
||||
from utils.views import JWTGenericViewMixin
|
||||
|
||||
|
||||
# Mixins
|
||||
|
|
@ -13,7 +13,7 @@ class LanguageViewMixin(generics.GenericAPIView):
|
|||
|
||||
|
||||
# Views
|
||||
class LanguageListView(LanguageViewMixin, JWTViewMixin, generics.ListAPIView):
|
||||
class LanguageListView(LanguageViewMixin, generics.ListAPIView):
|
||||
"""List view for model Language"""
|
||||
permission_classes = (permissions.AllowAny, )
|
||||
serializer_class = serializers.LanguageSerializer
|
||||
|
|
|
|||
|
|
@ -3,19 +3,20 @@ from collections import namedtuple
|
|||
from translation import models as translation_models
|
||||
from utils import exceptions
|
||||
from rest_framework.response import Response
|
||||
from rest_framework import status
|
||||
|
||||
|
||||
# JWT
|
||||
# Login base view mixin
|
||||
class JWTViewMixin(generics.GenericAPIView):
|
||||
class JWTGenericViewMixin(generics.GenericAPIView):
|
||||
"""JWT view mixin"""
|
||||
|
||||
ACCESS_TOKEN_HTTP = True
|
||||
ACCESS_TOKEN_HTTP_ONLY = True
|
||||
ACCESS_TOKEN_SECURE = False
|
||||
|
||||
REFRESH_TOKEN_HTTP = True
|
||||
REFRESH_TOKEN_HTTP_ONLY = True
|
||||
REFRESH_TOKEN_SECURE = False
|
||||
COOKIE = namedtuple('COOKIE', ['key', 'value', 'http', 'secure'])
|
||||
COOKIE = namedtuple('COOKIE', ['key', 'value', 'http_only', 'secure'])
|
||||
|
||||
def _check_locale(self, locale: str):
|
||||
|
||||
|
|
@ -24,10 +25,7 @@ class JWTViewMixin(generics.GenericAPIView):
|
|||
raise exceptions.LocaleNotExisted()
|
||||
return locale
|
||||
|
||||
def _put_data_in_cookies(self,
|
||||
locale: str,
|
||||
access_token: str,
|
||||
refresh_token: str):
|
||||
def _put_data_in_cookies(self, locale: str, access_token: str, refresh_token: str):
|
||||
"""
|
||||
CHECK locale in cookies and PUT access and refresh tokens there.
|
||||
cookies it is list that contain namedtuples
|
||||
|
|
@ -36,22 +34,21 @@ class JWTViewMixin(generics.GenericAPIView):
|
|||
COOKIES = list()
|
||||
|
||||
# Create locale namedtuple
|
||||
locale = self.COOKIE(key='locale',
|
||||
value=locale,
|
||||
http=True,
|
||||
secure=False)
|
||||
COOKIES.append(locale)
|
||||
_locale = self.COOKIE(key='locale',
|
||||
value=locale,
|
||||
http_only=True,
|
||||
secure=False)
|
||||
|
||||
# Write to cookie access and refresh token with secure flag
|
||||
_access_token = self.COOKIE(key='access_token',
|
||||
value=access_token,
|
||||
http=self.ACCESS_TOKEN_HTTP,
|
||||
http_only=self.ACCESS_TOKEN_HTTP_ONLY,
|
||||
secure=self.ACCESS_TOKEN_SECURE)
|
||||
_refresh_token = self.COOKIE(key='refresh_token',
|
||||
value=refresh_token,
|
||||
http=self.REFRESH_TOKEN_HTTP,
|
||||
http_only=self.REFRESH_TOKEN_HTTP_ONLY,
|
||||
secure=self.REFRESH_TOKEN_SECURE)
|
||||
COOKIES.extend((_access_token, _refresh_token))
|
||||
COOKIES.extend((_locale, _access_token, _refresh_token))
|
||||
return COOKIES
|
||||
|
||||
def _put_cookies_in_response(self, cookies: list, response: Response):
|
||||
|
|
@ -59,7 +56,8 @@ class JWTViewMixin(generics.GenericAPIView):
|
|||
for cookie in cookies:
|
||||
response.set_cookie(key=cookie.key,
|
||||
value=cookie.value,
|
||||
secure=cookie.secure)
|
||||
secure=cookie.secure,
|
||||
httponly=cookie.http_only)
|
||||
return response
|
||||
|
||||
def _get_tokens_from_cookies(self, request, cookies: dict = None):
|
||||
|
|
@ -67,13 +65,43 @@ class JWTViewMixin(generics.GenericAPIView):
|
|||
_cookies = request.COOKIES or cookies
|
||||
return [self.COOKIE(key='access_token',
|
||||
value=_cookies.get('access_token'),
|
||||
http=self.ACCESS_TOKEN_HTTP,
|
||||
http_only=self.ACCESS_TOKEN_HTTP_ONLY,
|
||||
secure=self.ACCESS_TOKEN_SECURE),
|
||||
self.COOKIE(key='refresh_token',
|
||||
value=_cookies.get('refresh_token'),
|
||||
http=self.REFRESH_TOKEN_HTTP,
|
||||
http_only=self.REFRESH_TOKEN_HTTP_ONLY,
|
||||
secure=self.REFRESH_TOKEN_SECURE)]
|
||||
|
||||
|
||||
class JWTCreateAPIView(JWTGenericViewMixin, generics.CreateAPIView):
|
||||
"""
|
||||
Concrete view for creating a model instance.
|
||||
"""
|
||||
def post(self, request, *args, **kwargs):
|
||||
_locale = request.COOKIES.get('locale')
|
||||
try:
|
||||
locale = self._check_locale(locale=_locale)
|
||||
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
|
||||
response = Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||
access_token, refresh_token = self._get_tokens_from_cookies(request)
|
||||
except exceptions.LocaleNotExisted:
|
||||
raise exceptions.LocaleNotExisted(locale=_locale)
|
||||
else:
|
||||
return self._put_cookies_in_response(
|
||||
cookies=self._put_data_in_cookies(locale=locale,
|
||||
access_token=access_token,
|
||||
refresh_token=refresh_token),
|
||||
response=response)
|
||||
|
||||
|
||||
class JWTRetrieveAPIView(JWTGenericViewMixin, generics.RetrieveAPIView):
|
||||
"""
|
||||
Concrete view for retrieving a model instance.
|
||||
"""
|
||||
def get(self, request, *args, **kwargs):
|
||||
"""Implement GET method"""
|
||||
_locale = request.COOKIES.get('locale')
|
||||
|
|
@ -87,7 +115,7 @@ class JWTViewMixin(generics.GenericAPIView):
|
|||
response = self.get_paginated_response(serializer.data)
|
||||
else:
|
||||
serializer = self.get_serializer(queryset, many=True)
|
||||
response = Response(serializer.data)
|
||||
response = Response(serializer.data, status.HTTP_200_OK)
|
||||
|
||||
access_token, refresh_token = self._get_tokens_from_cookies(request)
|
||||
|
||||
|
|
@ -99,3 +127,62 @@ class JWTViewMixin(generics.GenericAPIView):
|
|||
access_token=access_token,
|
||||
refresh_token=refresh_token),
|
||||
response=response)
|
||||
|
||||
|
||||
class JWTDestroyAPIView(JWTGenericViewMixin, generics.DestroyAPIView):
|
||||
"""
|
||||
Concrete view for deleting a model instance.
|
||||
"""
|
||||
def delete(self, request, *args, **kwargs):
|
||||
_locale = request.COOKIES.get('locale')
|
||||
try:
|
||||
locale = self._check_locale(locale=_locale)
|
||||
instance = self.get_object()
|
||||
instance.delete()
|
||||
response = Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
access_token, refresh_token = self._get_tokens_from_cookies(request)
|
||||
except exceptions.LocaleNotExisted:
|
||||
raise exceptions.LocaleNotExisted(locale=_locale)
|
||||
else:
|
||||
return self._put_cookies_in_response(
|
||||
cookies=self._put_data_in_cookies(locale=locale,
|
||||
access_token=access_token,
|
||||
refresh_token=refresh_token),
|
||||
response=response)
|
||||
|
||||
|
||||
class JWTUpdateAPIView(JWTGenericViewMixin, generics.UpdateAPIView):
|
||||
"""
|
||||
Concrete view for updating a model instance.
|
||||
"""
|
||||
def put(self, request, *args, **kwargs):
|
||||
_locale = request.COOKIES.get('locale')
|
||||
try:
|
||||
locale = self._check_locale(locale=_locale)
|
||||
partial = kwargs.pop('partial', False)
|
||||
instance = self.get_object()
|
||||
serializer = self.get_serializer(instance, data=request.data, partial=partial)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
|
||||
if getattr(instance, '_prefetched_objects_cache', None):
|
||||
# If 'prefetch_related' has been applied to a queryset, we need to
|
||||
# forcibly invalidate the prefetch cache on the instance.
|
||||
instance._prefetched_objects_cache = {}
|
||||
|
||||
response = Response(serializer.data)
|
||||
access_token, refresh_token = self._get_tokens_from_cookies(request)
|
||||
except exceptions.LocaleNotExisted:
|
||||
raise exceptions.LocaleNotExisted(locale=_locale)
|
||||
else:
|
||||
return self._put_cookies_in_response(
|
||||
cookies=self._put_data_in_cookies(locale=locale,
|
||||
access_token=access_token,
|
||||
refresh_token=refresh_token),
|
||||
response=response)
|
||||
|
||||
def patch(self, request, *args, **kwargs):
|
||||
kwargs['partial'] = True
|
||||
return self.put(request, *args, **kwargs)
|
||||
|
||||
|
|
|
|||
|
|
@ -7,3 +7,6 @@ SEND_SMS = False
|
|||
SMS_CODE_SHOW = True
|
||||
|
||||
DOMAIN_URI = 'localhost:8000'
|
||||
|
||||
# Increase access token lifetime for local deploy
|
||||
SIMPLE_JWT['ACCESS_TOKEN_LIFETIME'] = timedelta(days=365)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user