尽管 AllowAny 权限,django-rest-framework 在 POST、PUT、DELETE 上返回 403 响应 [英] django-rest-framework returning 403 response on POST, PUT, DELETE despite AllowAny permissions

查看:16
本文介绍了尽管 AllowAny 权限,django-rest-framework 在 POST、PUT、DELETE 上返回 403 响应的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆