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

时间:2015-09-18 13:39:34

标签: django authentication permissions django-rest-framework

我正在使用django-oneall来允许我网站上的社交登录会话身份验证。虽然它不是django-rest-framework的建议auth提供程序之一,但rest_framework.authentication.SessionAuthentication使用django的默认会话身份验证。所以我认为整合应该相当简单。

在权限方面,最终我将使用IsAdmin,但出于开发目的,我将其设置为IsAuthenticated。当返回403时,我放宽了AllowAny的权限,但仍然没有骰子。这是我的休息框架配置:

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和aa X-CSRFToken标题具有相同的值,我设置我的前端代码为所有ajax请求发送该标头,一切正常

3 个答案:

答案 0 :(得分:24)

Django REST Framework在几个相关情况下返回状态代码403

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

我将针对测试API发出一些演示请求,以提供每个示例,以帮助您诊断您遇到的问题并演示如何解决它。我将使用requests库。

测试API

我使用单个模型Life设置了一个非常简单的DRF API,其中包含单个字段(answer,默认值为42)。从现在开始,一切都很直接;我在ModelSerializer网址路由上设置了LifeSerializer - ModelViewSetLifeViewSet - DefaultRouter/life。我已将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

答案 1 :(得分:1)

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

答案 2 :(得分:0)

仅适用于可能会发现相同问题的任何人。 如果您使用的是没有路由器的视图集,例如:

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

除非您在类级别定义Permission_classes,否则Django Rest框架将返回403:

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

希望有帮助!