django-rest-framework在POST,PUT,DELETE上返回403响应,尽管有AllowAny权限

kadbb459  于 2022-12-14  发布在  Go
关注(0)|答案(5)|浏览(162)

我使用django-oneall来允许在我的站点上进行社交登录会话认证,虽然它不是django-rest-framework推荐的认证提供者之一,但是rest_framework.authentication.SessionAuthentication使用django默认的会话认证,所以我认为它应该很容易集成。
在权限方面,我最终会使用IsAdmin,但出于开发目的,我只是将其设置为IsAuthenticated。当返回403时,我将权限放宽到AllowAny,但仍然没有成功。以下是我的rest框架配置:

settings.py

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和一个相同值的X-CSRFToken Header,我设置了我的前端代码来发送所有 AJAX 请求的header,一切工作正常.

u0sqgete

u0sqgete1#

Django REST Framework在一些相关的情况下返回状态码403

  • 当您没有所需的权限级别时(例如,当DEFAULT_PERMISSION_CLASSES('rest_framework.permissions.IsAuthenticated',)时,以未经身份验证的用户身份发出API请求。
  • 当您执行不安全的请求类型(POST、PUT、PATCH或DELETE -应该有副作用的请求)时,您使用的是rest_framework.authentication.SessionAuthentication,并且您没有将CSRFToken包含在请求集中。
  • 当您正在执行不安全的请求类型,并且包含的CSRFToken不再有效时。

我将针对一个测试API发出几个演示请求,并给予每个请求的示例,以帮助您诊断所遇到的问题并演示如何解决它。

测试API

我用一个模型Life建立了一个非常简单的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
myzjeezk

myzjeezk2#

只是对于任何可能发现同样问题的人。如果您使用的是没有路由器的视图集,如:

user_list = UserViewSet.as_view({'get': 'list'})
user_detail = UserViewSet.as_view({'get': 'retrieve'})

Django Rest框架会返回403,除非你在类级别定义permission_classes:

class UserViewSet(viewsets.ModelViewSet):
    """
    A viewset for viewing and editing user instances.
    """
    permission_classes= YourPermisionClass

希望能有所帮助!

mbjcgjjk

mbjcgjjk3#

为了完整起见,还有一种DRF返回代码403的情况:如果您忘记将as_view()添加到您的www.example.com文件中的视图声明中urls.py。刚刚发生在我身上,我花了几个小时才找到问题所在,所以也许这个添加可以为某人保存一些时间。

igetnqfo

igetnqfo4#

对于那些甚至无法从Javascript访问其csrftoken的用户:
在我的例子中,我无法从我的Javascript代码中获取csrftoken,以便在 AJAX POST中设置它。它总是输出null。最后我发现django CSRF_COOKIE_HTTPONLY环境变量被设置为True。
来自Django文档

CSRF_饼干_HTTPONLY:如果将其设置为True,客户端JavaScript将无法访问CSRF Cookie。”

将CSRF_COOKIE_HTTPONLY更改为False使我最终获得了csrftoken。
https://docs.djangoproject.com/en/4.1/ref/settings/#std-setting-CSRF_COOKIE_HTTPONLY

kqlmhetl

kqlmhetl5#

还有一种情况是,当您在请求的“Authorization”标头中将令牌作为null传递时,在AllowAny路由上会出现403错误。例如,您可能希望允许任何人使用该路由,但也希望知道使用该路由的人是否是经过身份验证的用户。
例如

if (token) {
    headers = {
        "Content-Type": "application/json",
        "Authorization": "Token " + token
    }
} else {
    headers = {
        "Content-Type": "application/json"
    }
}

相关问题