2015-02-09 58 views
2

失蹤我有一個發送文件Django的一個Ajax請求,這是說,CSRF令牌丟失,但我複製了正在我的其他Ajax請求。我確信它與嘗試傳遞文件上傳有關。CSRF令牌上的文件上傳Ajax請求

我得到403和csrf丟失的回報。

base.html文件

<script type='text/javascript' src='http://code.jquery.com/jquery-1.8.2.js'></script> 
<script type="text/javascript"> 
    $(document).ready(function() { 
       $("#create_token").click(function() { 
         var username = document.getElementById("username").value; 
         $.ajax({ 
          url : "/gettoken/", 
          type : "POST", 
          dataType: "json", 
          data : { 
           csrfmiddlewaretoken: '{{ csrf_token }}', 
           create_token: 'create_token', 
           username: username, 
           }, 
           success : function(json) { 
            document.getElementById('output').innerHTML = ('Token: ' + json['token']); 
           }, 
           error : function(xhr,errmsg,err) { 
            console.log(xhr.status + ": " + xhr.responseText); 
            document.getElementById('output').innerHTML = "Token:" + " Request Failed."; 
           } 

         }); 
         return false; 
       }); 

       $("#add_friend").click(function() { 
         var token = document.getElementById("friend_token").value; 
         $.ajax({ 
          url : "/addfriend/", 
          type : "POST", 
          dataType: "json", 
          data : { 
           csrfmiddlewaretoken: '{{ csrf_token }}', 
           add_friend: token, 
           }, 
           success : function(json) { 
            document.getElementById('output').innerHTML = (json['message']); 
           }, 
           error : function(xhr,errmsg,err) { 
            console.log(xhr.status + ": " + xhr.responseText); 
            document.getElementById('output').innerHTML = "Request Failed."; 
           } 

         }); 
         return false; 
       }); 

       $("#uppropic").click(function() { 
         var file = document.getElementById("profile_pic").files[0]; 
         console.log(file); 
         $.ajax({ 
          url : "profilepic/", 
          type : "POST", 
          dataType: "json", 
          processData: false, 
          data : { 
           csrfmiddlewaretoken: '{{ csrf_token }}', 
           profile_pic: file, 
           }, 
           success : function(json) { 
            document.getElementById('output').innerHTML = (json['message']); 
           }, 
           error : function(xhr,errmsg,err) { 
            console.log(xhr.status + ": " + xhr.responseText); 
            document.getElementById('output').innerHTML = " Request Failed."; 
           } 

         }); 
         return false; 
       }); 


      }); 

home.html做爲

{% extends "base.html" %} 
{% block title %} 
{% for user in user_data %} 
    {{user.username}} 
{%endfor%} 
{% endblock %} 
{% block content %} 
    {% for user in user_data %} 
     Username: {{user.username}}<br> 
     First Name: {{user.first_name}}<br> 
     Last Name: {{user.last_name}}<br> 
     About: {{user.about}}<br> 
     Title: {{user.title}}<br> 
    {%endfor%} 
    Friends: 
    {% for friend in friend_data %} 
     {{friend}}<br> 
    {%endfor%} 
      {% if is_user_profile %} 
     <form method='POST' > 
     {% csrf_token %} 
     <input type='text' name='friend_token' id='friend_token'> 
     <button id='add_friend' name = 'add_friend' value='add_friend' > Add Friend </button> 
     </form> 

     <form method='POST' > 
     {% csrf_token %} 
     <button id='create_token' name = 'create_token' value='create_token' > Create Token </button> 
     {% for user in user_data %} 
     <input type='hidden' id='username' value='{{user.username}}'> 
     {%endfor%} 
     </form> 

     <p id='output'> 
     </p> 
     {%endif%} 

     <form method='POST'> 
     {% csrf_token %} 
     <input type='file' name='profile_pic' id='profile_pic'> 
     <button id='uppropic'> Upload Profile Pic</button> 
     {% for user in user_data %} 
     <input type='hidden' id='username' value='{{user.username}}'> 
     {%endfor%} 
     </form> 

    <a href="/logout/">Logout</a> 
{% endblock %} 

views.py

@login_required 
@csrf_protect  
def upload_profilepic(request): 
    context = {} 
    if request.method == 'POST': 
     post_data = request.POST.copy() 
     profile_pic = post_data['profile_pic'] 
     print post_data, profile_pic 
     handle_uploaded_file(request.FILES['file']) 
     context.update({'message':'You must select a file to upload.'}) 
     return HttpResponse(simplejson.dumps(context), content_type='application/json') 
    else: 
     context.update({'message':'You must select a file to upload.'}) 
     return HttpResponse(simplejson.dumps(context), content_type='application/json') 

consoleoutput

File { name: "10923328_1112855418728180_5377511192406844214_n.png", lastModified: 1421116207673, lastModifiedDate: Date 2015-01-13T02:30:07.673Z, size: 664332, type: "image/png" } home:56 
"403: 
<!DOCTYPE html> 
<html lang="en"> 
<head> 
    <meta http-equiv="content-type" content="text/html; charset=utf-8"> 
    <meta name="robots" content="NONE,NOARCHIVE"> 
    <title>403 Forbidden</title> 
    <style type="text/css"> 
    html * { padding:0; margin:0; } 
    body * { padding:10px 20px; } 
    body * * { padding:0; } 
    body { font:small sans-serif; background:#eee; } 
    body>div { border-bottom:1px solid #ddd; } 
    h1 { font-weight:normal; margin-bottom:.4em; } 
    h1 span { font-size:60%; color:#666; font-weight:normal; } 
    #info { background:#f6f6f6; } 
    #info ul { margin: 0.5em 4em; } 
    #info p, #summary p { padding-top:10px; } 
    #summary { background: #ffc; } 
    #explanation { background:#eee; border-bottom: 0px none; } 
    </style> 
</head> 
<body> 
<div id="summary"> 
    <h1>Forbidden <span>(403)</span></h1> 
    <p>CSRF verification failed. Request aborted.</p> 


</div> 

<div id="info"> 
    <h2>Help</h2> 

    <p>Reason given for failure:</p> 
    <pre> 
    CSRF token missing or incorrect. 
    </pre> 


    <p>In general, this can occur when there is a genuine Cross Site Request Forgery, or when 
    <a 
    href='http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ref-contrib-csrf'>Django's 
    CSRF mechanism</a> has not been used correctly. For POST forms, you need to 
    ensure:</p> 

    <ul> 
    <li>Your browser is accepting cookies.</li> 

    <li>The view function uses <a 
    href='http://docs.djangoproject.com/en/dev/ref/templates/api/#subclassing-context-requestcontext'><code>RequestContext</code></a> 
    for the template, instead of <code>Context</code>.</li> 

    <li>In the template, there is a <code>{% csrf_token 
    %}</code> template tag inside each POST form that 
    targets an internal URL.</li> 

    <li>If you are not using <code>CsrfViewMiddleware</code>, then you must use 
    <code>csrf_protect</code> on any views that use the <code>csrf_token</code> 
    template tag, as well as those that accept the POST data.</li> 

    </ul> 

    <p>You're seeing the help section of this page because you have <code>DEBUG = 
    True</code> in your Django settings file. Change that to <code>False</code>, 
    and only the initial error message will be displayed. </p> 

    <p>You can customize this page using the CSRF_FAILURE_VIEW setting.</p> 
</div> 

</body> 
</html> 
" 

做了一些研究後,問題與ajax請求將文件傳遞給django的方式相同,導致我的csrf錯誤。所以我試圖通過將csrf標記添加到formData來遵循其他人的做法。

這裏是有這個JQuery: post FormData AND csrf token together

以下設置搞亂了Ajax請求 過程數據堆棧後:假的, 的contentType:假的我已經看到了這個錯誤,

  $("#uppropic").click(function() { 
        var file = document.getElementById("profile_pic").files[0]; 
        console.log(file); 
        var csrf = '{{ csrf_token }}'; 
        console.log(csrf); 
        var formData = new FormData(document.getElementById("profile_pic_form")); 
        formData.append('csrfmiddlewaretoken', csrf); 
        console.log(formData); 

        $.ajax({ 
         url : "/profilepic/", 
         type : "POST", 
         dataType: "json", 
         processData: false, 
         contentType: false, 
         data : { 
          csrfmiddlewaretoken: '{{ csrf_token }}', 
          profile_pic: file, 
          }, 
          success : function(json) { 
           document.getElementById('output').innerHTML = (json['message']); 
          }, 
          error : function(xhr,errmsg,err) { 
           console.log(xhr.status + ": " + xhr.responseText); 
           document.getElementById('output').innerHTML = " Request Failed."; 
          } 

        }); 
        return false; 
      }); 
+0

將服務器端模板標籤混合到客戶端JavaScript通常不是一個好主意。像'{{...}}'應該在html中,或者如果你絕對必須的話,你應該把'var csrf ='{{csrf_token}}';'放在的腳本標籤中,其餘的JS應該放入。 js文件沒有任何模板標籤。這不會解決您的問題,但它會幫助您調試,因爲您可以「查看源代碼」並查看標記中的內容。 – sstur 2015-02-12 14:15:00

回答

1

一般當模板沒有設置csrf_token時。來自docs

如果您的視圖未呈現包含csrf_token模板標記的模板,則Django可能不會設置CSRF令牌cookie。在表單動態添加到頁面的情況下這很常見。爲了解決這個問題,Django提供了一個強制設置cookie的視圖裝飾器:ensure_csrf_cookie()

是渲染文件上傳表單設置令牌的頁面?也許{% if is_user_profile %}條件評估爲False並且令牌未設置?

,你可以嘗試使用@ensure_csrf_cookie裝飾在您查看呈現文件上傳表單,如果沒有別的幫助。

<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %> 
<sec:csrfMetaTags /> 
<script type="text/javascript"> 
    var csrfParameter = $("meta[name='_csrf_parameter']").attr("content"); 
    var csrfHeader = $("meta[name='_csrf_header']").attr("content"); 
    var csrfToken = $("meta[name='_csrf']").attr("content"); 
</script> 

該請求的數據是這樣的::

var file = document.getElementById("rawdatafile"); 
var completeData = new FormData(); 
completeData.append("rawData", file.files[0]); 

而在Ajax的請求我做:

+0

如果is_user_profile真的是不真實的我只是確保只有當用戶在他們的個人資料上他們看到的選項發佈,並添加好友。我正在做一個添加朋友的獨特方式,我不會討論,但那只是我通過的一個變種。事情是在這個頁面上有三種其他形式,他們正在工作。他們工作並完美通過ajax請求。沒有任何形式的文件上傳,因爲即時通訊使用該文件,即時通訊與一個Ajax請求傳遞給views.py然後我保存該文件。文件位置被保存在該用戶的數據庫中。 – 2015-02-09 04:20:01

+0

嘿,我添加了更多信息。 – 2015-02-09 06:01:26

0

我通過添加以下到我的頭上,部分解決了這個問題

$.ajax({ 
    type: "POST", 
    url: "<c:url value='/myurl/etc' />", 
    headers: {'X-CSRF-TOKEN': csrfToken}, 
    cache: false, 
    processData: false, 
    contentType: false, 
    data: completeData, 
    dataType: "text", 
    ... 

這樣我就可以上傳多部分文件並通過http頭傳遞csrf標記。