Django REST Framework 在几种相关情况下返回状态码403:
- 当您没有所需的权限级别时(例如,当
DEFAULT_PERMISSION_CLASSES 为 ('rest_framework.permissions.IsAuthenticated',) 时,以未经身份验证的用户身份发出 API 请求。
- 当您执行不安全的请求类型(POST、PUT、PATCH 或 DELETE - 应该有副作用的请求)时,您使用的是
rest_framework.authentication.SessionAuthentication,并且您没有在请求集中包含您的 CSRFToken。
- 当您执行不安全的请求类型并且您包含的 CSRFToken 不再有效时。
我将针对测试 API 发出一些演示请求,以提供每个示例,以帮助您诊断遇到的问题并展示如何解决它。我将使用requests 库。
测试 API
我使用单个模型 Life 设置了一个非常简单的 DRF API,其中包含单个字段(answer,默认值为 42)。从现在开始的一切都非常简单。我在/life URL 路由上设置了ModelSerializer - LifeSerializer、ModelViewSet - LifeViewSet 和DefaultRouter。我已将 DRF 配置为要求用户通过身份验证才能使用 API 并使用 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