【问题标题】:Forbidden HTTP 403 DRF + ReactJS request.session禁止 HTTP 403 DRF + ReactJS request.session
【发布时间】:2020-12-19 06:51:33
【问题描述】:

我正在使用 DjangoRestFramework 和 ReactJS 开发一个测验应用程序。我的应用由两个应用组成,apifrontend。在我的 api 应用程序中,我有多个 API 视图用于许多不同的事情。我的 API 视图之一称为 JoinQuiz。当我在 frontend 上调用它时,我在控制台中收到此错误:

Forbidden: /api/join-quiz
[16/Dec/2020] "POST /api/join-quiz HTTP/1.1" 403 58

我不认为我的问题是由于 CSRF 错误,因为我的其他 API 视图工作正常。在这一点上我可能错了。

[16/Dec/2020] "GET /api/get-question?id=3 HTTP/1.1" 200 10009 
[17/Dec/2020 01:15:47] "POST /api/create-quiz HTTP/1.1" 201 11959

我怀疑我的request.session 可能是问题,因为当我直接转到/api/join-quiz 并使用我的code 发出POST 请求时,没有任何问题,并且我的帖子成功了。

文件

Views.py

class QuizView(generics.ListAPIView):
    queryset = Quiz.objects.all()
    serializer_class = QuizSerializer

class GetQuiz(APIView):
    """ Searches for a quiz given its code and returns the Quiz with is_host info"""
    serializer_class = QuizSerializer
    lookup_url_kwarg = 'code'

    def get(self, request, format=None): # This is an HTTP GET request
        code = request.GET.get(self.lookup_url_kwarg)
        if code != None: # Check if code is not equal to None
            quiz = Quiz.objects.filter(code=code)
            if len(quiz) > 0: # If there is a quiz...
                data = QuizSerializer(quiz[0]).data
                data['is_host'] = self.request.session.session_key == quiz[0].host
                

                return Response(data, status=status.HTTP_200_OK)

            return Response({'Quiz not found': 'Invalid Code'}, status=status.HTTP_404_NOT_FOUND)
        return Response({'Bad Request': 'Code Parameter not found in request'}, status=status.HTTP_400_BAD_REQUEST)
        

        
class CreateQuizView(APIView):
    """Creates A new Quiz given nested question and answer data"""
    serializer_class = QuizSerializer

    def post(self, request, format=None):
        """ Create the User's Account first"""
        if not self.request.session.exists(self.request.session.session_key):
            self.request.session.create()
        
        data = request.data
        data['host'] = self.request.session.session_key
        serializer = self.serializer_class(data=data)

        if serializer.is_valid():
            
            quiz = serializer.create(validated_data=data)
            self.request.session['quiz_code'] = quiz.code

            return Response(
                self.serializer_class(quiz).data, 
                status=status.HTTP_201_CREATED
                )


        return Response({'Bad Request': 'Invalid Data'}, status=status.HTTP_400_BAD_REQUEST)

        
class JoinQuiz(APIView):
    """Join a quiz based on the quiz code"""
    lookup_url_kwarg = 'code'

    def post(self, request, format=None):
        if not self.request.session.exists(self.request.session.session_key):
            self.request.session.create()

        print(self.request.session.session_key)
        code = request.data.get(self.lookup_url_kwarg)

        if code != None:
            quiz_result = Quiz.objects.filter(code=code)
            if len(quiz_result) > 0:

                self.request.session['quiz_code'] = code
                return Response({'message': 'Quiz Joined!'}, status=status.HTTP_200_OK)
            
            return Response({'Quiz Not Found': 'Invalid Quiz Code'}, status=status.HTTP_404_NOT_FOUND)
        
        return Response({'Bad Request': 'Invalid Post Data'}, status=status.HTTP_400_BAD_REQUEST)
        

serializers.py




class QuizSerializer(serializers.ModelSerializer):
    
    questions = serializers.PrimaryKeyRelatedField(many=True, read_only=True)

    class Meta:
        model = Quiz
        fields = ['id', 'code', 'questions', 'name']

    def create(self, validated_data):
        questions_data = validated_data.pop('questions')

        quiz = Quiz.objects.create(**validated_data)

        for question_data in questions_data:
            
            answers_data = question_data.pop('answers')
            question = Question.objects.create(quiz=quiz, **question_data)

            for answer_data in answers_data: 
                Answer.objects.create(question=question, **answer_data)

        return quiz

前端请求

  const quizButtonPressed = () => {
      const requestOptions = {
          method: "POST",
          headers: {"Content-Type": "application/json"},
          body: JSON.stringify({
              code: quizCode
          })
      };
      fetch('/api/join-quiz', requestOptions)
      .then((response) => {
          if (response.ok) {
              props.history.push(`/play/${quizCode}`);
          } else {
              setError("Quiz not found")
          }        
      })
      .catch((error) => console.log(error));
  }

编辑

我遵循了@Blusky 的解决方案,它奏效了!

按照@Blusky 的 Django 文档链接解决了问题:https://docs.djangoproject.com/en/3.1/ref/csrf/#ajax

【问题讨论】:

    标签: python reactjs django post django-rest-framework


    【解决方案1】:

    即使您检查过,也可能是 CSRF 问题。您应该检查 403 错误的正文,它可能包含更多信息。

    只有经过身份验证后,Django 上的 POST 请求才需要 CSRF 令牌(这可能是您的第一个 POST 工作的原因)

    如果是这样,你可以查看这个sn-p:https://docs.djangoproject.com/en/3.1/ref/csrf/#ajax

    【讨论】:

    • 成功了!非常感谢,我刚刚假设 CSRF 与我的问题无关,因为它适用于我的其他请求。 Django 文档链接对实现CSRF 令牌非常有帮助。
    猜你喜欢
    • 2012-01-08
    • 1970-01-01
    • 2011-07-12
    • 1970-01-01
    • 1970-01-01
    • 2020-08-18
    • 1970-01-01
    • 1970-01-01
    • 2021-03-21
    相关资源
    最近更新 更多