【问题标题】:Django REST framework TokenAuthentication returns anonymous userDjango REST 框架 TokenAuthentication 返回匿名用户
【发布时间】:2021-09-26 03:24:51
【问题描述】:

当我尝试登录时,如何在请求对象不返回匿名用户的情况下正确实现 DRF TokenAuthentication?

根据docs,当通过身份验证时,TokenAuthentication 对象提供了作为 Django 用户实例的request.user 和作为令牌实例的request.auth。但即使经过身份验证,request.user 也会返回匿名用户。

我做错了什么?

客户请求:

//function to get token
export default function axiosConfig() {
    // request header
    const headers = {
        "Content-Type": "application/json"
    }

    // Get token from local storage. Token is stored when user registers.
    const token = localStorage.getItem("token");

    if (token) headers["Authorisation"] = `Token ${token}`;

    return headers;

}

Redux 操作

import axiosConfig from "../../utils/axiosConfig";

const config = axiosConfig

export const login = (email, password) => (dispatch, getState) => {

    const body = { email, password };

    // Change to absoulte path when deploying to production
    axios
        .post("http://localhost:8000/api/auth/login", body, config())
        .then((res) => {
            dispatch({
                type: SIGN_IN_SUCCESFUL,
                payload: res.data,
            });
            console.log(res);
        })
        .catch((err) => {
            dispatch({
                type: SIGN_IN_FAIL,
                payload: err.response,
            });
            console.log(err.response.data, err.response.status);
        });
};

Django

网址:

from django.urls import path
from authentication.views import RegisterationView
from authentication.views import LoginView
from authentication.views import LogoutView

urlpatterns = [
    path("auth/register", RegisterationView.as_view()),
    path("auth/login", LoginView.as_view()),
    path("auth/logout/<int:id>", LogoutView.as_view()),
]

序列化器:

LoginResponseSerializer 用于向客户端提供响应数据

class LoginSerializer(serializers.Serializer):
    """Login serializer"""

    username = serializers.CharField()
    password = serializers.CharField(required=True)


class LoginResponseSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = [
            "id",
            "username",
            "first_name",
            "last_name",
            "email",
            "is_active",
            "is_staff",
        ]

        read_only_fields = ["id", "is_active", "is_staff"]

查看:

class LoginView(APIView):
    """Login View"""

    permision_classs = [permissions.AllowAny]

    def post(self, request):
        serializer = LoginSerializer(data=request.data)

        if serializer.is_valid():
            print(serializer.data) # Data is present

            user = authenticate(request, **serializer.data) # Valid credentials. User object is returned.
            response_serializer = LoginResponseSerializer(user)

            if user is not None and login(request, user):
                print(request.user) # User is anonymous

                token, created_token = Token.objects.get_or_create(user_id=user.id)

                if isinstance(created_token, Token):
                    token = created_token

                return Response(
                    {
                        "user": response_serializer.data,
                        "status": {
                            "message": "user authenticated",
                            "code": status.HTTP_200_OK,
                        },
                        "token": token.key,
                    }
                )

            raise serializers.ValidationError(
                "Invalid Username or Password. Please try again"
            )

        return Response(
            {"error": serializer.errors, "status": status.HTTP_403_FORBIDDEN}
        )

【问题讨论】:

  • 你也可以展示你的中间件吗?

标签: python django django-rest-framework django-views http-token-authentication


【解决方案1】:

由于您使用的是令牌身份验证,因此对于每个请求,您的用户都将使用标头中的令牌进行身份验证。

Django login() 在 SessionAuthentication 的情况下很有用。用户存储在 django 中的 session 对象中,由 session cookie 标识。

在您看来,您不必调用登录方法。只需返回token 以及您想要的任何额外信息。并确保在每个请求中发送此token 以验证此用户。

编辑: DRF 文档中关于request.user 的说明是关于在您在标头中提供令牌的另一个视图中访问经过身份验证的用户。

【讨论】:

  • @Sedan A. 你是对的。后来我意识到我正在实现 TokenAuthentication,因为我认为它是一个 SessionAuthentication。令牌认证只需要验证令牌并返回适当的响应。我从setting.pyDEFAULT_AUTHENTICATION_CLASSES 列表中删除了login() 并丢弃了SessionAuthentication,因为它在TokenAuthentication 之前并且中断了流程。
猜你喜欢
  • 1970-01-01
  • 2018-10-21
  • 1970-01-01
  • 2018-05-21
  • 2016-06-06
  • 2017-02-05
  • 2016-04-19
  • 2017-08-21
相关资源
最近更新 更多