【问题标题】:Getting 403 on POST在 POST 上获取 403
【发布时间】:2016-03-09 22:38:57
【问题描述】:

我正在学习使用 Django Rest Framework 并按照教程进行操作。我根据教程创建了一个简单的索引,它适用于 GET,但不适用于 POST:

@api_view(['GET','POST'])
def game_list(request):
    if request.method == 'GET':
        games = Game.objects.all()
        serializer = GameSerializer(games, many=True)
        return Response(serializer.data)
    elif request.method == 'POST':
        serializer = GameSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

我将默认设置设置为AllowAny

REST_FRAMEWORK = {
    # Use Django's standard `django.contrib.auth` permissions,
    # or allow read-only access for unauthenticated users.
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.AllowAny'
    ]
}

但当我尝试使用POST 使用Firefox RESTClient 进行任何操作时,我仍然得到HTTP 403。 I read 我必须添加一个 X-CSRFToken 标头和 cookie 才能正常工作,但我没有这些。

【问题讨论】:

  • “我没有这些”是什么意思?您没有启用 CSRF 保护?你试过csrf_exempt吗?
  • 您必须将其与您的发布请求一起传递。当您访问网站中的任何页面时,它存在于会话中,并且可以被视为 cookie。 docs.djangoproject.com/en/1.7/ref/contrib/csrf/#csrf-ajax
  • @ChrisHawkes 我明白了,但我想确切地了解发生了什么。 RESTClient 仅发送我自己放入的标头。我根本没有这方面的会话信息。当我执行干净的 GET 时,响应标头中没有任何 cookie 或会话信息。
  • 我认为 csrftoken 仅在帖子中是必需的,但是对于像以前的评论者所说的那样进行测试,您可以在您的视图上进行该方法调用,从而免除 csrf
  • @ChrisHawkes 是的,这可能在上一步中起作用;-))。我继续我的教程,APIView 似乎不支持@csrf_exempt 注释...

标签: django django-rest-framework


【解决方案1】:

来自文档:

默认情况下,如果传入请求未通过 CsrfViewMiddleware 执行的检查,则会向用户发送“403 Forbidden”响应。这通常只有在存在真正的跨站请求伪造时才能看到,或者由于编程错误,CSRF 令牌未包含在 POST 表单中。

另外,如官方文档所述,CSRF默认是开启的,你需要在你的AJAX请求中添加一个X-CSRFToken。

这是文档中的代码:

// using jQuery
function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie != '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) == (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}

var csrftoken = getCookie('csrftoken');

function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

请记住,文档建议使用 jquery 的 ajaxSetup 方法,这不是推荐的方法,因为它会改变其他脚本使用 ajax 函数的方式,因此最好将特定的 CSRF 代码添加到您的自定义 JS 代码如下:

$.ajax({
    method: 'POST',
    url: 'your.url.com/',
    beforeSend: function(xhr, settings) {
        if (!WU._csrfSafeMethod(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    },
    success: function(msg)
    {}
});

参考:https://docs.djangoproject.com/en/1.9/ref/csrf/#ajax

【讨论】:

  • 如果你想禁用 Django Rest Framework CSRF,这不是推荐的行为,检查这个:stackoverflow.com/a/30875830/4848267
  • 我没有任何 cookie。我不使用 AJAX。我只是使用 REST 测试工具进行简单的 HTTP 调用。
  • 然后,如果您不验证 WS 客户端,您可以安全地删除 CSRF 检查,如我之前的评论中所述:)
  • 这似乎奏效了。我现在肯定遇到了一个不同的错误(数据验证的问题,所以我猜 CSRF 的事情是固定的)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-04
  • 1970-01-01
  • 2018-01-07
  • 2021-11-18
  • 2016-03-03
相关资源
最近更新 更多