如何将csrf_令牌包含到dropzone Post请求(Django)中

2024-06-26 10:53:30 发布

您现在位置:Python中文网/ 问答频道 /正文

好吧,事情解决了。只是编辑以防有人遇到同样的问题。在

在同一个javascript文件中添加在注释中标记为answer的代码。 定义时

var myDropzone =  new Dropzone(...
  ...//More stuff here
  headers:{
    'X-CSRFToken' : csrftoken
  }

就这样。在

所以当我通过提交POST请求时,我得到了一个403禁止dropzone.js到詹戈。詹戈显示了一条消息,说我没有包括CSRF令牌,但我不知道如果我不在HTML中使用表单,该如何实际包含它。在

文件_表单.html在

^{pr2}$

升降带-引导程序.js在

$(function() {
  var previewNode = document.querySelector("#template");
  previewNode.id = "";
  var previewTemplate = previewNode.parentNode.innerHTML;
  previewNode.parentNode.removeChild(previewNode);

  var myDropzone = new Dropzone(document.querySelector("#container-dropzone") , {
    url: "/dashby/files/add/", //url to make the request to.
    thumbnailWidth: 80,
    thumbnailHeight: 80,
    parallelUploads: 20,
    previewTemplate: previewTemplate,
    autoQueue: false,
    previewsContainer: "#previews",
    clickable: ".file-input-button",
    headers: { // Tried to apply the token this way but no success.
      'X-CSRFToken': $('meta[name="token"]').attr('content')
    }
  });

  myDropzone.on("addedfile", function(file){
    file.previewElement.querySelector(".start").onclick = function(){
      myDropzone.enqueueFile(file);
      };
  });

  myDropzone.on("totaluploadprogress", function(progress){
    document.querySelector("#total-progress .progress-bar").style.width = progress + "%";
  });

  myDropzone.on("sending", function(file){
    // Show total progress on start and disable START button.
    document.querySelector("#total-progress").style.opacity = "1";
    file.previewElement.querySelector(".start").setAttribute("disabled", "disabled");
  });

  // Hide progress bar when complete.
  myDropzone.on("queuecomplete", function(progress){
    document.querySelector("#total-progress").style.opacity = "0";
  });

  // Setup buttons for every file.
  document.querySelector("#actions .start").onclick = function(){
    myDropzone.enqueueFiles(myDropzone.getFilesWithStatus(Dropzone.ADDED));
  };
  document.querySelector("#actions .cancel").onclick = function(){
    myDropzone.removeAllFiles(true);
  };
});

在我的基本.htmlim添加所有必需的文件(dropzone、jquery、bootstrap和我的自定义javascript文件)

对于django表单处理:

在视图.py在

class DocumentCreate(CreateView):
    model = Document
    fields = ['file']
    def form_valid(self, form):
        self.object = form.save()
        data = {'status': 'success'}
        response = JSONResponse(data, mimetype =
        response_mimetype(self.request))
        return response

我的“文档”模型

class Document(models.Model):
    file = models.FileField(upload_to = 'files/',
                                validators=[validate_file_type])
    uploaded_at = models.DateTimeField(auto_now_add = True)
    extension = models.CharField(max_length = 30, blank = True)
    thumbnail = models.ImageField(blank = True, null = True)

    def clean(self):
        self.file.seek(0)
        self.extension = self.file.name.split('/')[-1].split('.')[-1]
        if self.extension == 'xlsx' or self.extension == 'xls':
            self.thumbnail = 'xlsx.png'
        elif self.extension == 'pptx' or self.extension == 'ppt':
            self.thumbnail = 'pptx.png'
        elif self.extension == 'docx' or self.extension == 'doc':
            self.thumbnail = 'docx.png'

    def delete(self, *args, **kwargs):
        #delete file from /media/files
        self.file.delete(save = False)
        #call parent delete method.
        super().delete(*args, **kwargs)

    #Redirect to file list page.
    def get_absolute_url(self):
        return reverse('dashby-files:files')

    def __str__(self):
        #cut the 'files/'
        return self.file.name.split('/')[-1]

    class Meta():
        #order by upload_date descending
        #for bootstrap grid system. (start left side)
        ordering = ['-uploaded_at']

我创建了一个Json响应来处理dropzone。在

在响应.py在

from django.http import HttpResponse
import json

MIMEANY = '*/*'
MIMEJSON = 'application/json'
MIMETEXT = 'text/plain'

# Integrating Dropzone.js with Django.
def response_mimetype(request):
    can_json = MIMEJSON in request.META['HTTP_ACCEPT']
    can_json |= MIMEANY in request.META['HTTP_ACCEPT']
    return MIMEJSON if can_json else MIMETEXT

# Custom HttpResponse
class JSONResponse(HttpResponse):
    def __init__(self, obj='', json_opts=None, mimetype=MIMEJSON,
                *args, **kwargs):
        json_opts = json_opts if isinstance(json_opts, dict) else {}
        content = json.dumps(obj, **json_opts)
        super(JSONResponse, self).__init__(content, mimetype,
                                          *args, **kwargs)

我已经被这个问题困扰了一天,所以决定在这里寻求帮助,因为我还没有找到一个。在

感谢所有花时间阅读的人以及我能得到的任何帮助/提示。在


Tags: toselfjsononrequestdefextensionfunction
3条回答

只需将{% csrf_token %}放在Html文件中的任何位置。它是自动添加的

 <input type="hidden" name="csrfmiddlewaretoken" value="**************" />

在向服务器发送数据之前,只需添加额外的字段csrf_token,其值为$("input[name='csrfmiddlewaretoken']").val();

Django的文档有一个reference for this

While [a special parameter] can be used for AJAX POST requests, it has some inconveniences: you have to remember to pass the CSRF token in as POST data with every POST request. For this reason, there is an alternative method: on each XMLHttpRequest, set a custom X-CSRFToken header to the value of the CSRF token. This is often easier, because many JavaScript frameworks provide hooks that allow headers to be set on every request.
[…]

Acquiring the token is straightforward:

// 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');

[…] Finally, you’ll have to actually set the header on your AJAX request, while protecting the CSRF token from being sent to other domains using settings.crossDomain in jQuery 1.5.1 and newer:

function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
});

如果在开始发出请求之前运行这两个代码块,它应该可以正常工作™. 在

总之,只需使用以下代码块:

// from https://docs.djangoproject.com/en/1.10/ref/csrf/ via http://stackoverflow.com/a/39776325/5244995.
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({
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
});

docs建议从cookie而不是DOM获取CSRF令牌。试试看。在

相关问题 更多 >