尽管 AllowAny 权限,django-rest-framework 在 POST、PUT、DELETE 上返回 403 响应 [英] django-rest-framework returning 403 response on POST, PUT, DELETE despite AllowAny permissions
问题描述
我正在使用 django-oneall 来允许在我的网站上进行社交登录会话身份验证.虽然它不是 django-rest-framework 建议的身份验证提供程序之一,但 rest_framework.authentication.SessionAuthentication
使用 django 的默认会话身份验证.所以我认为集成应该相当简单.
I'm using a django-oneall to allow social login session authentication on my site. While it isn't one of the suggested auth providers for django-rest-framework, rest_framework.authentication.SessionAuthentication
uses django's default session authentication. so I thought it should be fairly simple to integrate.
在权限方面,我最终将使用 IsAdmin
,但出于开发目的,我只是将其设置为 IsAuthenticated
.当返回 403 时,我放宽了对 AllowAny
的权限,但仍然没有骰子.这是我的休息框架配置:
On the permissions side, ultimately I'll use IsAdmin
, but for development purposes, I just had it set to IsAuthenticated
. When that returning 403s, I relaxed the permissions to AllowAny
, but still no dice. Here's my rest framework config:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.AllowAny',
# 'rest_framework.permissions.IsAuthenticated',
# 'rest_framework.permissions.IsAdminUser',
),
'PAGE_SIZE': 100,
'DEFAULT_FILTER_BACKENDS': (
'rest_framework.filters.DjangoFilterBackend',
),
}
我根据以下答案进行了这项工作.事实证明,rest_framework
期望 csrftoken
cookie 和 aa X-CSRFToken
标头具有相同的值,我将前端代码设置为为所有 ajax 请求发送该标头,一切正常.
I got this working based on the answer below. It turns out that rest_framework
expects both the csrftoken
cookie and a a X-CSRFToken
Header of the same value, I setup my front-end code to send that header for all ajax requests and everything worked fine.
推荐答案
Django REST Framework 在几种相关情况下返回状态代码 403
:
Django REST Framework returns status code 403
under a couple of relevant circumstances:
- 当您没有所需的权限级别时(例如,当
DEFAULT_PERMISSION_CLASSES
为('rest_framework.permissions.IsAuthenticated',)
时,以未经身份验证的用户身份发出 API 请求. - 当您执行不安全的请求类型(POST、PUT、PATCH 或 DELETE - 应该有副作用的请求)时,您使用的是
rest_framework.authentication.SessionAuthentication
并且您没有包含您的请求集中的 CSRFToken. - 当您执行不安全的请求类型并且您包含的 CSRFToken 不再有效时.
- When you don't have the required permission level (e.g. making an API request as an unauthenticated user when
DEFAULT_PERMISSION_CLASSES
is('rest_framework.permissions.IsAuthenticated',)
. - When you doing an unsafe request type (POST, PUT, PATCH or DELETE - a request that should have side effects), you are using
rest_framework.authentication.SessionAuthentication
and you've not included your CSRFToken in the requeset. - When you are doing an unsafe request type and the CSRFToken you've included is no longer valid.
我将针对测试 API 发出一些演示请求,以给出每个示例的示例,以帮助您诊断遇到的问题并展示如何解决它.我将使用 requests
库.
I'm going to make a few demo requests against a test API to give an example of each to help you diagnose which issue you are having and show how to resolve it. I'll be using the requests
library.
测试 API
我使用单个模型 Life
设置了一个非常简单的 DRF API,其中包含一个字段(answer
,默认值为 42代码>).从现在开始的一切都非常简单;我设置了一个
ModelSerializer
- LifeSerializer
、一个 ModelViewSet
- LifeViewSet
和一个 DefaultRouter
> 在 /life
URL 路由上.我已将 DRF 配置为要求对用户进行身份验证才能使用 API 并使用 SessionAuthentication
.
I set up a very simple DRF API with a single model, Life
, that contains a single field (answer
, with a default value of 42
). Everything from here on out is pretty straight forward; I set up a ModelSerializer
- LifeSerializer
, a ModelViewSet
- LifeViewSet
, and a DefaultRouter
on the /life
URL route. I've configured DRF to require user's be authenticated to use the API and to use SessionAuthentication
.
点击 API
import json
import requests
response = requests.get('http://localhost:8000/life/1/')
# prints (403, '{"detail":"Authentication credentials were not provided."}')
print response.status_code, response.content
my_session_id = 'mph3eugf0gh5hyzc8glvrt79r2sd6xu6'
cookies = {}
cookies['sessionid'] = my_session_id
response = requests.get('http://localhost:8000/life/1/',
cookies=cookies)
# prints (200, '{"id":1,"answer":42}')
print response.status_code, response.content
data = json.dumps({'answer': 24})
headers = {'content-type': 'application/json'}
response = requests.put('http://localhost:8000/life/1/',
data=data, headers=headers,
cookies=cookies)
# prints (403, '{"detail":"CSRF Failed: CSRF cookie not set."}')
print response.status_code, response.content
# Let's grab a valid csrftoken
html_response = requests.get('http://localhost:8000/life/1/',
headers={'accept': 'text/html'},
cookies=cookies)
cookies['csrftoken'] = html_response.cookies['csrftoken']
response = requests.put('http://localhost:8000/life/1/',
data=data, headers=headers,
cookies=cookies)
# prints (403, '{"detail":"CSRF Failed: CSRF token missing or incorrect."}')
print response.status_code, response.content
headers['X-CSRFToken'] = cookies['csrftoken']
response = requests.put('http://localhost:8000/life/1/',
data=data, headers=headers,
cookies=cookies)
# prints (200, '{"id":1,"answer":24}')
print response.status_code, response.content
这篇关于尽管 AllowAny 权限,django-rest-framework 在 POST、PUT、DELETE 上返回 403 响应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!