簡體   English   中英

在 Django Rest 框架中使用 Tokenauthentication 進行身份驗證時,last_login 字段未更新

[英]last_login field is not updated when authenticating using Tokenauthentication in Django Rest Framework

我正在一個項目中工作,該項目依賴於 DjangoRestFramework 下的 Django 用戶 model 和 TokenAuthentication

我被要求獲取每個用戶的上次登錄日期時間,並且我意識到當我調用身份驗證 REST 端點時,該字段沒有得到更新。

這是眾所周知的事實嗎? 為了在每次調用令牌身份驗證時更新該字段,我是否遺漏了一些我必須做的事情?

謝謝

好吧,最后我繼承自 REST Framework TokenAuthentication,在 urls 文件中指向它

url(r'^api-token-auth/', back_views.TokenAuthenticationView.as_view()),

視圖處理請求並手動調用 update_last_login ,如下所示:

from django.contrib.auth.models import update_last_login

class TokenAuthenticationView(ObtainAuthToken):
    """Implementation of ObtainAuthToken with last_login update"""

    def post(self, request):
        result = super(TokenAuthenticationView, self).post(request)
        try:
            request_user, data = requests.get_parameters(request)
            user = requests.get_user_by_username(data['username'])
            update_last_login(None, user)            
        except Exception as exc:
            return None
        return result

@FDF 的回答很棒。 這是另一種方法。

我們發送將調用update_last_login user_logged_in信號:

user_logged_in.send(sender=user.__class__, request=request, user=user)

這是一個工作視圖(基於使用電子郵件作為 USERNAME_FIELD 的自定義用戶模型):

from rest_framework import parsers, renderers
from rest_framework.authtoken.models import Token
from rest_framework.response import Response
from rest_framework.views import APIView

from django.contrib.auth.signals import user_logged_in
from emailauth.serializers import AuthTokenSerializer, UserSerializer


class ObtainAuthToken(APIView):
    throttle_classes = ()
    permission_classes = ()
    parser_classes = (parsers.FormParser, parsers.MultiPartParser, parsers.JSONParser,)
    renderer_classes = (renderers.JSONRenderer,)
    serializer_class = AuthTokenSerializer

    def post(self, request, *args, **kwargs):
        serializer = self.serializer_class(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.validated_data['user']
        token, created = Token.objects.get_or_create(user=user)
        user_logged_in.send(sender=user.__class__, request=request, user=user)
        return Response({'token': token.key, 'user': UserSerializer(user).data})


obtain_auth_token = ObtainAuthToken.as_view()

您可以在此處找到完整的源代碼: 更新了 last_login 的 Api View

希望這可以幫助。

一種更清潔的方法:

from django.contrib.auth.models import update_last_login
from rest_framework.authtoken.models import Token
from rest_framework.authtoken.views import ObtainAuthToken

class LoginToken(ObtainAuthToken):
    def post(self, request, *args, **kwargs):
        result = super().post(request, *args, **kwargs)
        token = Token.objects.get(key=result.data['token'])
        update_last_login(None, token.user)
        return result

然后設置 urls.py:

url(r'^api-token-auth/', views.LoginToken.as_view()),

我對Django==2.0.5回答, django-rest-framework-social-oauth2==1.1.0

from django.contrib.auth import user_logged_in
from oauth2_provider.models import AccessToken
from rest_framework import status
from rest_framework_social_oauth2.views import TokenView

class MyTokenView(TokenView):
    def post(self, request, *args, **kwargs):
        response = super().post(request, *args, **kwargs)
        if response.status_code == status.HTTP_200_OK:
            token = AccessToken.objects.get(token=response.data['access_token'])
            user = token.user
            user_logged_in.send(sender=type(user), request=request, user=user)
        return response

網址.py:

from django.urls import path

urlpatterns = [
    path('token', MyTokenView.as_view(), name='token'),
]

這是我使用 ViewSet 的解決方案:

視圖.py:

from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.authtoken.serializers import AuthTokenSerializer
from rest_framework import viewsets
from django.contrib.auth.models import update_last_login

class LoginViewSet(viewsets.ViewSet):
    """Checks email and password and returns an auth token."""

    serializer_class = AuthTokenSerializer

    def create(self, request):
        """Use the ObtainAuthToken APIView to validate and create a token."""

        ##update last_login
        try:
            user = models.User.objects.get(email = request.data['username'])
            update_last_login(None, user)
        except:
            pass

        return ObtainAuthToken().post(request)

現在只需將此視圖集添加到 urls.py:

router.register('login', views.LoginViewSet, base_name="login")

這是 django 3.0.8 的最新代碼。
:)
謝謝 FDF!

from django.contrib.auth.models import update_last_login
from rest_framework.authtoken.views import ObtainAuthToken
from django.contrib.auth import get_user_model


class TokenAuthenticationView(ObtainAuthToken):
    """Implementation of ObtainAuthToken with last_login update"""
    
    def post(self, request):
        result = super(TokenAuthenticationView, self).post(request)
        currentUserModel = get_user_model()
        try:
            user = currentUserModel.objects.get(username=request.data['username'])
            update_last_login(None, user)
        except Exception as exc:
            return None
        return result

通過信號實現

from django.dispatch import receiver
from django.db.models.signals import post_save
from django.contrib.auth import user_logged_in

from oauth2_provider.models import AccessToken


@receiver(post_save, sender=AccessToken)
def post_save_access_token(instance, created, raw, **kwargs):
    if not created or raw:
        return
    user_logged_in.send(sender=instance.user.__class__,  user=instance.user)

對於使用 knox 對用戶進行身份驗證的任何人,則需要編輯 api.py 文件並導入 user_logged_in,如下所示

from django.contrib.auth.signals import user_logged_in

之后,在同一 api.py 文件中的 LoginAPI 類中,在 _, token = AuthToken.objects.create(user) 之后添加以下行,如下所示

user_logged_in.send(sender=user.__class__, request=request, user=user)

如果您將 Simple JWT 用於 Django,您可以通過以下鏈接輕松完成。 你只需要添加

SIMPLE_JWT = {
...,
'UPDATE_LAST_LOGIN': True,
...,
}

有時您不想要確切的登錄時間,因為前端存儲令牌並使用它而無需再次登錄。

您可以通過從rest_framework APIView來保存用戶通過身份驗證和授權的每個請求中的當前時間

from django.contrib.auth.models import update_last_login
from rest_framework.views import APIView

class CustomAPIView(APIView):
    def check_permissions(self, request):
        super().check_permissions(request)
        # here user is authorized (otherwise an exception would have been raised)
        update_last_login(None, request.user)

class my_endpoint(CustomAPIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, company_id=None):
        ...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM