From 3f5d56fb7a042b96271efab5957bb1713a8d89d3 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Tue, 20 Aug 2019 17:44:46 +0300 Subject: [PATCH] added to login endpoint parameter "remember" in request body --- apps/authorization/serializers/common.py | 17 ++++++++++++++++- apps/authorization/views/common.py | 23 +++++++++++++++++++++++ apps/utils/views.py | 19 +++++++++++++------ project/settings/base.py | 4 ++++ 4 files changed, 56 insertions(+), 7 deletions(-) diff --git a/apps/authorization/serializers/common.py b/apps/authorization/serializers/common.py index 8808c53b..bb3a9541 100644 --- a/apps/authorization/serializers/common.py +++ b/apps/authorization/serializers/common.py @@ -114,11 +114,18 @@ class LoginByUsernameOrEmailSerializer(JWTBaseSerializerMixin, serializers.Model username_or_email = serializers.CharField(write_only=True) password = serializers.CharField(write_only=True) + # for cookie properties (Max-Age) + remember = serializers.BooleanField(write_only=True) + class Meta: """Meta-class""" model = account_models.User fields = ( - 'username_or_email', 'password', 'refresh_token', 'access_token' + 'username_or_email', + 'password', + 'remember', + 'refresh_token', + 'access_token' ) def validate(self, attrs): @@ -138,6 +145,14 @@ class LoginByUsernameOrEmailSerializer(JWTBaseSerializerMixin, serializers.Model self.instance = user return attrs + def to_representation(self, instance): + """Override to_representation method""" + token = self.get_token() + setattr(instance, 'access_token', str(token.access_token)) + setattr(instance, 'refresh_token', str(token)) + # setattr(instance, 'remember', self.validated_data.get('remember')) + return super().to_representation(instance) + class RefreshTokenSerializer(serializers.Serializer): """Serializer for refresh token view""" diff --git a/apps/authorization/views/common.py b/apps/authorization/views/common.py index 34991c47..f57be4d5 100644 --- a/apps/authorization/views/common.py +++ b/apps/authorization/views/common.py @@ -210,6 +210,29 @@ class LoginByUsernameOrEmailView(JWTAuthViewMixin): permission_classes = (permissions.AllowAny,) serializer_class = serializers.LoginByUsernameOrEmailSerializer + def post(self, request, *args, **kwargs): + """Implement POST method""" + _locale = self._get_locale(request) + 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_200_OK) + + access_token = serializer.data.get('access_token') + refresh_token = serializer.data.get('refresh_token') + is_permanent = serializer.validated_data.get('remember') + 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, + permanent=is_permanent), + response=response) + # Refresh access_token class RefreshTokenView(JWTGenericViewMixin): diff --git a/apps/utils/views.py b/apps/utils/views.py index 87563681..90338ca2 100644 --- a/apps/utils/views.py +++ b/apps/utils/views.py @@ -7,6 +7,7 @@ from rest_framework.response import Response from translation import models as translation_models from utils import exceptions from rest_framework_simplejwt import tokens +from django.conf import settings # JWT @@ -22,7 +23,7 @@ class JWTGenericViewMixin(generics.GenericAPIView): REFRESH_TOKEN_HTTP_ONLY = False REFRESH_TOKEN_SECURE = False - COOKIE = namedtuple('COOKIE', ['key', 'value', 'http_only', 'secure']) + COOKIE = namedtuple('COOKIE', ['key', 'value', 'http_only', 'secure', 'max_age']) def _create_jwt_token(self, user) -> dict: """Return dictionary with pairs access and refresh tokens""" @@ -46,7 +47,8 @@ class JWTGenericViewMixin(generics.GenericAPIView): def _put_data_in_cookies(self, locale: str, access_token: str = None, - refresh_token: str = None): + refresh_token: str = None, + permanent: bool = None): """ CHECK locale in cookies and PUT access and refresh tokens there. cookies it is list that contain namedtuples @@ -58,18 +60,21 @@ class JWTGenericViewMixin(generics.GenericAPIView): _locale = self.COOKIE(key='locale', value=locale, http_only=self.LOCALE_HTTP_ONLY, - secure=self.LOCALE_SECURE) + secure=self.LOCALE_SECURE, + max_age=None if permanent else settings.COOKIES_MAX_AGE) # Write to cookie access and refresh token with secure flag if access_token and refresh_token: _access_token = self.COOKIE(key='access_token', value=access_token, http_only=self.ACCESS_TOKEN_HTTP_ONLY, - secure=self.ACCESS_TOKEN_SECURE) + secure=self.ACCESS_TOKEN_SECURE, + max_age=None if permanent else settings.COOKIES_MAX_AGE) _refresh_token = self.COOKIE(key='refresh_token', value=refresh_token, http_only=self.REFRESH_TOKEN_HTTP_ONLY, - secure=self.REFRESH_TOKEN_SECURE) + secure=self.REFRESH_TOKEN_SECURE, + max_age=None if permanent else settings.COOKIES_MAX_AGE) COOKIES.extend((_access_token, _refresh_token)) COOKIES.append(_locale) return COOKIES @@ -85,12 +90,14 @@ class JWTGenericViewMixin(generics.GenericAPIView): value=cookie.value, secure=cookie.secure, httponly=cookie.http_only, + max_age=cookie.max_age, domain='.id-east.ru') else: response.set_cookie(key=cookie.key, value=cookie.value, secure=cookie.secure, - httponly=cookie.http_only) + httponly=cookie.http_only, + max_age=cookie.max_age,) return response def _get_tokens_from_cookies(self, request, cookies: dict = None): diff --git a/project/settings/base.py b/project/settings/base.py index 08095c84..97c0ee04 100644 --- a/project/settings/base.py +++ b/project/settings/base.py @@ -359,3 +359,7 @@ PASSWORD_RESET_TIMEOUT_DAYS = 1 CONFIRMATION_PASSWORD_RESET_TEMPLATE = 'account/password_reset_confirm.html' RESETTING_TOKEN_TEMPLATE = 'account/password_reset_email.html' CONFIRM_EMAIL_TEMPLATE = 'account/confirm_email.html' + + +# COOKIES +COOKIES_MAX_AGE = 86400 # 24 hours