You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django登录接口遇CSRF验证失败403错误,求原因及解决方法

CSRF Verification Failed on Django REST Framework Login View

Hey there, let's break down why you're hitting this CSRF error and fix it step by step. Your code is on the right track, but there are a few key adjustments and checks needed to resolve the issue.

Why This Error Happens

  1. Decorator Precedence Issue: Even though you added @csrf_exempt, Django REST Framework's @api_view wraps your function into a class-based view under the hood. If the decorators aren't ordered correctly, the csrf_exempt rule might not apply properly to the final view.
  2. Session Authentication Conflict: By default, DRF includes SessionAuthentication in its global auth settings. This means even if you're using Token Authentication, DRF will still enforce CSRF checks for requests that involve session cookies.
  3. Incorrect Testing Method: If you're testing the login with a standard browser form submission (instead of an API client like Postman or curl), browsers automatically handle CSRF cookies—but your view is designed for API requests that don't rely on session-based CSRF validation.

Fixes to Try

1. Adjust Decorator Order (Ensure @csrf_exempt Takes Effect)

For DRF function views, @csrf_exempt needs to be applied outside the @api_view decorator to ensure it wraps the view that DRF creates. Here's the corrected order:

from django.shortcuts import render
from rest_framework.status import (
    HTTP_400_BAD_REQUEST,
    HTTP_404_NOT_FOUND,
    HTTP_200_OK
)
from rest_framework.decorators import api_view
from rest_framework.response import Response
from django.contrib.auth import authenticate
from django.views.decorators.csrf import csrf_exempt
from rest_framework.authtoken.models import Token
from rest_framework.decorators import permission_classes
from rest_framework.permissions import AllowAny

@csrf_exempt
@api_view(["POST"])
@permission_classes((AllowAny,))
def login(request):
    username = request.data.get("username")
    password = request.data.get("password")
    if username is None or password is None:
        return Response({'error': 'Please provide both username and password'}, status=HTTP_400_BAD_REQUEST)
    user = authenticate(username=username, password=password)
    if not user:
        return Response({'error': 'Invalid Credentials'}, status=HTTP_404_NOT_FOUND)
    token, _ = Token.objects.get_or_create(user=user)
    return Response({'token': token.key}, status=HTTP_200_OK)

2. Remove Session Authentication from Global Settings (Token-Only APIs)

If your project only uses Token Authentication for APIs, edit your settings.py to remove SessionAuthentication from the default auth classes. This stops DRF from enforcing CSRF checks for token-based requests:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',
        # Remove this line: 'rest_framework.authentication.SessionAuthentication'
    ],
    # ... other DRF settings ...
}

3. Switch to Class-Based APIView (Cleaner Control)

Using DRF's APIView class gives you clearer control over CSRF and permissions. Here's how to rewrite your login view with explicit CSRF exemption:

from django.shortcuts import render
from rest_framework.status import (
    HTTP_400_BAD_REQUEST,
    HTTP_404_NOT_FOUND,
    HTTP_200_OK
)
from rest_framework.views import APIView
from rest_framework.response import Response
from django.contrib.auth import authenticate
from rest_framework.authtoken.models import Token
from rest_framework.permissions import AllowAny
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator

@method_decorator(csrf_exempt, name='dispatch')
class LoginView(APIView):
    permission_classes = [AllowAny]

    def post(self, request):
        username = request.data.get("username")
        password = request.data.get("password")
        if username is None or password is None:
            return Response({'error': 'Please provide both username and password'}, status=HTTP_400_BAD_REQUEST)
        user = authenticate(username=username, password=password)
        if not user:
            return Response({'error': 'Invalid Credentials'}, status=HTTP_404_NOT_FOUND)
        token, _ = Token.objects.get_or_create(user=user)
        return Response({'token': token.key}, status=HTTP_200_OK)

Then update your urls.py to use this class view:

from django.urls import path
from .views import LoginView

urlpatterns = [
    path('login/', LoginView.as_view(), name='login'),
    # ... other URLs ...
]

4. Test with an API Client

If you were testing with a browser form, switch to tools like Postman, curl, or Thunder Client. These tools don't send session cookies by default, so CSRF checks won't trigger for token-based requests. Example curl command:

curl -X POST http://your-domain/login/ -d "username=your-username&password=your-password"

内容的提问来源于stack exchange,提问作者lohith devapatla

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:04:54