2015-02-09 56 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标记。