首页 > 解决方案 > django.contrib.auth.login() 函数不返回任何已登录的用户

问题描述

我使用 Django 的内置身份验证系统创建了一个基本应用程序。我成功地使用在 shell 中创建了一个用户对象 >>python manage.py createsuperuser

然后,我创建了一个基本视图“UserLogin”以及相应的序列化程序/url,以使用 django.contrib.auth authenticate() 和 login() 函数登录现有用户。在使用我创建的用户的凭据进行测试后,登录功能似乎已经成功运行。

为了测试这一点,我创建了另一个视图函数“CurrentUser”,它返回当前登录用户的用户名。但是,此视图将用户返回为空。

为什么“当前用户”视图不会返回已登录的用户?我在下面附上了我的代码(减去导入)。

视图.py:

class UserLogin(APIView):
    def post(self, request, format = None):
        serializer = UserLoginSerializer(data=request.data)
        if serializer.is_valid():
            user = authenticate(username=serializer.validated_data["username"], password=serializer.validated_data["password"])
            if user is not None:
                login(request, user)
                return Response(UserSerializer(user).data, status=status.HTTP_201_CREATED)
            return Response("Invalid username/password", status=status.HTTP_401_UNAUTHORIZED)
        return Response(serializer.errors, status=status.HTTP_401_UNAUTHORIZED)

class CurrentUser(APIView):
    def get(self, request, format = None):
        return Response(self.request.user.username)

序列化程序.py:

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['id', 'username']

class UserLoginSerializer(serializers.Serializer):
    username = serializers.CharField(max_length=300, required=True)
    password = serializers.CharField(required=True, write_only=True)

网址.py:

urlpatterns = [
    path('login/', views.UserLogin.as_view()),
    path('current/', views.CurrentUser.as_view())
]

任何指导将不胜感激。

谢谢

标签: pythondjangorestauthenticationdjango-rest-framework

解决方案


您必须在 DRF 设置中将默认身份验证类设置为会话身份验证类。在此处阅读有关它的更多信息 [1]。

会话身份验证使用会话 ID 来识别用户。因此,您必须在请求中发送基于 cookie 的会话 ID。在此处阅读有关会话身份验证的信息 [2]。

例如:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.SessionAuthentication', # <-- set this class
    ]
}

使用此代码:

def post(self, request, format = None):
    serializer = UserLoginSerializer(data=request.data)
    if serializer.is_valid():
        user = authenticate(username=serializer.validated_data["username"], password=serializer.validated_data["password"])
        if user:
            return Response(UserSerializer(user).data, status=status.HTTP_201_CREATED)
        return Response("Invalid username/password", status=status.HTTP_401_UNAUTHORIZED)
    return Response(serializer.errors, status=status.HTTP_401_UNAUTHORIZED)

但我的建议是使用 Token auth [3]。

要使用令牌身份验证 2,事情会发生变化:

  1. DRF 设置中的默认身份验证类
  2. 向任何 DRF API 视图发送请求时,您将 Auth 标头发送为Token <token-value>

您的 post 方法和 API 视图代码将保持不变。

[1] https://www.django-rest-framework.org/api-guide/authentication/#setting-the-authentication-scheme

[2] https://www.django-rest-framework.org/api-guide/authentication/#sessionauthentication

[3] https://www.django-rest-framework.org/api-guide/authentication/#tokenauthentication


推荐阅读