[英]DRF asking for CSRF Token with TokenAuthentication as the only auth method
[英]DRF loses CSRF token with PUT method
我的項目中有一個常規的ModelViewSet
,它與GET
和POST
請求完美配合,但對PUT
失敗,返回此錯誤:
{
"detail": "CSRF Failed: CSRF token missing or incorrect."
}
這是我的urls.py :
from django.urls import path,re_path,include
from django.utils.text import slugify,camel_case_to_spaces
from PaymentsManagerApp import views, models
from rest_framework import routers
APP_NAME = 'PaymentsManagerApp'
router = routers.DefaultRouter()
router.register(r'payments', views.PaymentViewSet)
payments_list = views.PaymentViewSet.as_view({
'get':'list',
'post':'create'
})
payment_detail = views.PaymentViewSet.as_view({
'get':'retrieve',
'put':'update',
'patch':'partial_update',
'delete':'destroy'
})
def urlpattern_from_route(route):
if "regex" in route and route['regex']:
path_method = re_path
else:
path_method = path
return path_method(route['path'],route['view'].as_view(),name=route['name'] if "name" in route else None)
routes_views = list(map(urlpattern_from_route,routes))
route_services = [
payment_detail = views.PaymentViewSet.as_view({
'get':'retrieve',
'put':'update',
'patch':'partial_update',
'delete':'destroy'
})
route_services = [
path('payments/', payments_list, name='rest_payments_list'),
path('payments/<int:pk>/', payment_detail, name='rest_payment_detail'),
]
urlpatterns = routes_views + route_services
這是我的views.py :
import os
import json
from datetime import datetime, timedelta
from django.shortcuts import render
from PaymentsManagerApp import urls, models, serializers
from FrontEndApp import urls as Fronturls
from django.shortcuts import render,redirect
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.contenttypes.models import ContentType
from django.views.generic import View
from django.contrib.auth.models import Permission
from GeneralApp.utils import get_catalogs
from django.contrib.staticfiles import finders
from django.utils.text import slugify,camel_case_to_spaces
from rest_framework import viewsets, permissions
from rest_framework.response import Response
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.response import Response
from rest_framework.filters import OrderingFilter, SearchFilter
from django.db.models import Q
class PaymentViewSet(viewsets.ModelViewSet):
exclude_from_schema = True
permission_classes = (permissions.IsAuthenticated,)
queryset = models.Payment.objects.all()
serializer_class = serializers.PaymentSerializer
filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter,)
search_fields = ('payment_type', 'creation_user__username', 'provider__name', 'invoice', 'payment_method_type', 'payment_document_number')
filter_fields = ('id', 'payment_type', 'creation_user', 'provider', 'is_payment_requested', 'is_paid', 'payment_method_type')
當我發送GET或POST到payments_manager/payments/
,它可以很好地工作。 另外,當我將GET發送到pyments_manager/payments/<int:pk>/
它也很好用。
問題是當我將PUT發送到payments_manager/payments/<int:pk>/
,因為我得到以下信息:
我不知道為什么,但是DRF丟失了登錄的用戶信息(您可以看到登錄標簽,而不是用戶名)。
編輯
這是我在settings.py中的 REST_FRAMEWORK:
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAuthenticated',),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
),
'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',),
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 20,
'DEFAULT_METADATA_CLASS': 'rest_framework.metadata.SimpleMetadata'
}
編輯我發現僅當我使用DRF默認界面( 127.0.0.1:8000/es/payments_manager/payments/1/
)從瀏覽器直接訪問端點時,錯誤才會出現:
我的PUT請求可以從我的javascript ajax完美地工作。
為了使用會話身份驗證並執行POST
(有點怪異)/ PUT
/ PATCH
/ DELETE
/等,您必須傳遞標頭。
參見: https : //github.com/django/django/blob/8b3f1c35dd848678225e8634d6880efeeab5e796/django/middleware/csrf.py#L306
我還為您創建了一個小測試:
response = self.client.post('/session-login/', data={'username': 'user', 'password': 'pass'})
self.assertEqual(302, response.status_code)
self.assertIn('csrftoken', response.cookies)
self.assertIn('sessionid', response.cookies)
# Don't want to go through the trouble of having to get the CSRF from the login form
self.client.handler.enforce_csrf_checks = True
csrftoken = self.client.cookies.get('csrftoken').value
# NOTE: The only reason this works it's because we're passing a header along with the request.
response = self.client.patch('/payments/%s/' % (self.payment.id), content_type='application/json',
data=json.dumps({'is_paid': 'Y'}), HTTP_X_CSRFTOKEN=csrftoken)
self.assertEqual(200, response.status_code)
self.assertEqual('Y', response.json()['is_paid'])
# NOTE: The reason this DOES NOT works it's because we're NOT passing a header along with the request.
response = self.client.patch('/payments/%s/' % (self.payment.id), content_type='application/json',
data=json.dumps({'is_paid': 'N'}))
self.assertEqual(403, response.status_code)
編輯。
添加了一個用戶,登錄后導航到localhost/payments/
並添加了一條記錄,然后轉到記錄localhost/payments/1/
並對其進行了更新( PUT
)。 一切正常。 請添加您的django / drf版本。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.