4

我在我的 Django 项目中使用私有视图来处理 AJAX 请求。

def HereIsSomeJSON(request, label):
    if not request.method == "POST":
        raise PermissionDenied
    # Here is the job of my AJAX, basically feeding a JSON
    json = {...}

    return HttpResponse(json, "application/json")

使用 JavaScript,我请求使用 jQuery 的 AJAX,如下所示:

function FeedMeWithJSON() {
    // Django needs his Cross-Site Request Forgery token to welome POST datas
    oPostDatas = {
        'csrfmiddlewaretoken': '{{ csrf_token }}'
    };
    jQuery.post("/url/to/HereIsSomeJSON", oPostDatas, function(oData, sStatus) {
        // Here is the job to be done with the fetched JSON
    }, "json");
}

由于request.method我在视图中进行的验证,一切正常。用户无法手动(通过在浏览器中输入我的 AJAX url)访问我的视图。

但是,由于我需要更多 AJAX 视图,我想知道我是否做对了。所以我想创建一个自定义的 Django 装饰器,我可以在我的每一个 AJAX 视图上方使用它。

是保护我的私人意见的好方法吗?如果是这样,我该怎么做?

谢谢,

编辑


显然,这还不够清楚。我正在使用 Django 视图来执行 AJAX 请求。但我不希望用户能够输入 URL 来读取数据库内容。我知道人们总是可以使用curl或类似的东西来发送 POST 数据,从而绕过我的东西,即使他必须发送正确的{% csrf_token %}.

另外,在不久的将来登录功能将被实现,我将添加@login_required装饰器。

谢谢,

4

3 回答 3

5

您要求 POST 为您的 ajax 视图的方法基本上是可以的,并且有一个现有的装饰器来处理它:

from django.views.decorators.http import require_POST

@require_POST
def my_view(request):
    # I can assume now that only POST requests make it this far
    # ...
    pass

此外,还有一种更简单的方法可以将 CSRF 令牌添加到您的 jQuery AJAX 调用中,记录在这里。基本思想是您从 cookie 中读取 CSRF 令牌,并使用beforeSend选项 in$.ajaxSetup将其添加到您的所有$.ajax调用中(包括快捷语法,如$.post)。

由于此代码不依赖于模板变量,因此它不必位于内联<script>标记中。

// 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));
}
$.ajaxSetup({
    crossDomain: false, // obviates need for sameOrigin test
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type)) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
});
于 2013-05-15T16:14:34.747 回答
1

正如@armonge所说,仅检查 POST 方法并不能提供任何保护。假设您需要一些检查,该用户已注册并且可能具有一些权限或所需的属性。为此,可以使用这样的装饰器(可能需要自定义):

def apply_permissions(view_func):
    def _wrapped_view(request, *args, **kwargs):
        # it is possible to add some other checks, that return booleans
        # or do it in a separate `if` statement
        # for example, check for some user permissions or properties
        permissions = [
            request.is_ajax(),
            request.method == "POST",
            request.user.is_authenticated()
        ]
        if not all(permissions):
            raise PermissionDenied
        return view_func(request, *args, **kwargs)
    return _wrapped_view


@apply_permissions
def HereIsSomeJSON(request, label):
    # your code here without any permissions checks

    # Here is the job of my AJAX, basically feeding a JSON
于 2013-05-15T16:29:12.803 回答
0

我发现要求 POST 是不够的,curl例如,可能会作弊。

这就是为什么定制装饰器是 - 在我看来 - 要走的路。

from django.http import HttpResponseBadRequest


def require_AJAX(function):
    """Return a bad request instance if the view is not using AJAX
    function -- the view
    """

    def wrap(request, *args, **kwargs):
        if not request.is_ajax():
            return HttpResponseBadRequest()
        return function(request, *args, **kwargs)

    wrap.__doc__ = function.__doc__
    wrap.__name__ = function.__name__
    return wrap

这个装饰器实际上比@stalk 少,但这是我需要的。

于 2013-08-13T15:33:08.403 回答