diff --git a/api/v1/auth.py b/api/v1/auth.py index ea99f40c..e09d27c5 100644 --- a/api/v1/auth.py +++ b/api/v1/auth.py @@ -1,28 +1,41 @@ +from datetime import timedelta + from django.contrib.auth import get_user_model from django.utils.translation import ugettext_lazy as _ +from django.shortcuts import get_object_or_404 +from django.utils.timezone import now from rest_framework import serializers from rest_framework.authtoken.views import ObtainAuthToken from rest_framework.compat import authenticate +from rest_framework.response import Response +from rest_framework.views import APIView +from rest_framework.authtoken.models import Token +from rest_framework import status + +from apps.auth.models import TempToken User = get_user_model() class AuthTokenSerializer(serializers.Serializer): - email = serializers.CharField(label=_("Email")) + user_id = serializers.IntegerField(required=False) + email = serializers.CharField(label=_("Email"), required=False) password = serializers.CharField( label=_("Password"), style={'input_type': 'password'}, - trim_whitespace=False + trim_whitespace=False, + required=False, ) def validate(self, attrs): + user_id = attrs.get('user_id') email = attrs.get('email') password = attrs.get('password') + request = self.context.get('request') if email and password: - user = authenticate(request=self.context.get('request'), - email=email, password=password) + user = authenticate(request=request, email=email, password=password) # The authenticate call simply returns None for is_active=False # users. (Assuming the default ModelBackend authentication @@ -33,6 +46,8 @@ class AuthTokenSerializer(serializers.Serializer): elif user.role != User.ADMIN_ROLE: msg = _('Only admin have permission to login admin page.') raise serializers.ValidationError(msg, code='authorization') + elif user_id and request.user.is_authenticated and request.user.role == User.ADMIN_ROLE: + user = get_object_or_404(User, pk=user_id) else: msg = _('Must include "email" and "password".') raise serializers.ValidationError(msg, code='authorization') @@ -43,3 +58,18 @@ class AuthTokenSerializer(serializers.Serializer): class ObtainToken(ObtainAuthToken): serializer_class = AuthTokenSerializer + + +class ObtainTempToken(APIView): + + def get(self, request): + user_id = request.GET.get('user') + if user_id and request.user.is_authenticated and request.user.role == User.ADMIN_ROLE: + user = get_object_or_404(User, pk=user_id) + token, created = TempToken.objects.get_or_create(user=user) + if not created and now() - token.created > timedelta(hours=1): + token.delete() + token = TempToken.objects.create(user=user) + return Response({'temp_token': token.key}) + return Response(status=status.HTTP_400_BAD_REQUEST) + diff --git a/api/v1/urls.py b/api/v1/urls.py index 0eafbe10..f4e57664 100644 --- a/api/v1/urls.py +++ b/api/v1/urls.py @@ -6,7 +6,7 @@ from rest_framework.routers import DefaultRouter from drf_yasg.views import get_schema_view from drf_yasg import openapi -from .auth import ObtainToken +from .auth import ObtainToken, ObtainTempToken from .views import ( AuthorBalanceViewSet, AuthorRequestViewSet, BanerViewSet, ConfigViewSet, CategoryViewSet, @@ -64,6 +64,7 @@ schema_view = get_schema_view( urlpatterns = [ path('api-token-auth/', ObtainToken.as_view(), name='api-token-auth'), + path('temp-auth-token/', ObtainTempToken.as_view(), name='temp-auth-token'), path('configs/', ConfigViewSet.as_view(), name='configs'), path('swagger(.json|.yaml)', schema_view.without_ui(cache_timeout=None), name='schema-json'), path('swagger/', schema_view.with_ui('swagger', cache_timeout=None), name='schema-swagger-ui'), diff --git a/apps/auth/middleware.py b/apps/auth/middleware.py index 1c737a93..f954bd6f 100644 --- a/apps/auth/middleware.py +++ b/apps/auth/middleware.py @@ -1,8 +1,13 @@ +from datetime import timedelta + from django.contrib.auth import login from django.utils.deprecation import MiddlewareMixin +from django.utils.timezone import now from rest_framework.authtoken.models import Token +from apps.auth.models import TempToken + class TokenAuthLoginMiddleware(MiddlewareMixin): @@ -16,3 +21,20 @@ class TokenAuthLoginMiddleware(MiddlewareMixin): login(request, user) except Token.DoesNotExist: pass + + +class TempTokenAuthLoginMiddleware(MiddlewareMixin): + + def process_request(self, request): + if 'temp-token' in request.GET: + token = request.GET.get('temp-token') + if token: + try: + token = TempToken.objects.get(key=token) + if now() - token.created > timedelta(hours=1): + token.delete() + return + user = token.user + login(request, user) + except TempToken.DoesNotExist: + pass diff --git a/apps/auth/models.py b/apps/auth/models.py index 71a83623..d95d3f20 100644 --- a/apps/auth/models.py +++ b/apps/auth/models.py @@ -1,3 +1,8 @@ from django.db import models -# Create your models here. +from rest_framework.authtoken.models import Token + + +class TempToken(Token): + class Meta: + app_label = 'auth' diff --git a/project/settings.py b/project/settings.py index 8cdb2ed2..5d5ca021 100644 --- a/project/settings.py +++ b/project/settings.py @@ -80,6 +80,7 @@ MIDDLEWARE = [ 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'apps.auth.middleware.TokenAuthLoginMiddleware', + 'apps.auth.middleware.TempTokenAuthLoginMiddleware', ] ROOT_URLCONF = 'project.urls'