在ajax登录后提交不同表单时出现CSRF令牌错误

时间:2015-07-30 02:19:11

标签: ajax django django-csrf

页面包含两个表单,一个用于身份验证,另一个用于提问。通过AJAX调用提交auth表单并成功登录用户。但是,如果用户在登录后提交问题表单,则会抛出“CSRF令牌丢失或不正确”。

main.js

$(function() {
    // Submit post on submit
    $('#login-form').on('submit', function(event){
        event.preventDefault();
        console.log("form submitted!")
        create_post();
    });

    // AJAX for auth
    function create_post() {
        $.ajax({
            url : "perfil/entrar/", // the endpoint
            type : "POST", // http method
            data : { username : $('#username-text').val(), password : $('#password-text').val() }, // data sent with the post request
            // handle a successful response
            success : function(json) {
                $('#username-text').val(''); // remove the value from the input
                $('#password-text').val(''); // remove the value from the input
            },
            // handle a non-successful response
            error : function(xhr,errmsg,err) {
                console.log(xhr.status + ": " + xhr.responseText); // provide a bit more info about the error to the console
            }
        });
    };


    // This function gets cookie with a given name
    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');

    /*
    The functions below will create a header with csrftoken
    */

    function csrfSafeMethod(method) {
        // these HTTP methods do not require CSRF protection
        return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }
    function sameOrigin(url) {
        // test that a given url is a same-origin URL
        // url could be relative or scheme relative or absolute
        var host = document.location.host; // host + port
        var protocol = document.location.protocol;
        var sr_origin = '//' + host;
        var origin = protocol + sr_origin;
        // Allow absolute or scheme relative URLs to same origin
        return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
            (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
            // or any other URL that isn't scheme relative or absolute i.e relative.
            !(/^(\/\/|http:|https:).*/.test(url));
    }

    $.ajaxSetup({
        beforeSend: function(xhr, settings) {
            if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) {
                // Send the token to same-origin, relative URLs only.
                // Send the token only if the method warrants CSRF protection
                // Using the CSRFToken value acquired earlier
                xhr.setRequestHeader("X-CSRFToken", csrftoken);
            }
        }
    });
    // Open modal dialog for authentification
    $('#myModal').on('shown.bs.modal', function () {
      $('#myInput').focus()
    });

});

的index.html

            <form method="post" id=class="form-horizontal" action="/perguntar/">
                {% csrf_token %}
                        <div class="col-md-7">
                        {{ questionform.title }}
                        {{ questionform.title.errors }}
                        {{ questionform.body }}
                        {{ questionform.body.errors }}
                        </div>
                        <div class="form-group">
                            <div class="col-sm-4">
                                <div class="input-group">
                                    <div class="input-group-addon">$</div>
                                    <div>{{ questionform.orcamento }}</div>
                                    {{ questionform.orcamento.errors }}
                                    <div class="input-group-addon">,00</div>
                                </div>
                                {{ questionform.category }}
                                {{ questionform.category.errors }}
                                <button type="submit" class="btn btn-primary btn-block">Perguntar</button>
                            </div>
                        </div>
            </form>

                        <form method="POST" id="login-form">
                          {% csrf_token %}
                        <label for="username-text">Usuario:</label>
                        <input type="text" name="username" value="" id="username-text">
                        <label for="password-text">Senha:</label>
                        <input type="password" name="password" value="" id="password-text">
                        <input type="submit" value="login" />
                        <input type="hidden" name="next" value="{{ next|escape }}" />
                       </form>

login_view

def login_view(request):
    if request.method == 'POST':
        response_data = {}
        username = request.POST.get('username', '')
        password = request.POST.get('password', '')
        user = auth.authenticate(username=username, password=password)
        if user is not None and user.is_active:
            auth.login(request, user)
            response_data['result'] = 'success'
            return HttpResponse(
                        json.dumps(response_data),
                        content_type="application/json"
            )
        else:
            return render(request, 'error.html', {
        })
    else:
        return render(request, 'login.html', {
        })

askQuestion_view

def perguntar(request):
    if request.method == 'POST':
        form = ModelThreadForm(request.POST)
        if form.is_valid():
            thread = form.save(commit=False)
            if request.user.is_authenticated():
                thread.published = True
                thread.creator = request.user
                thread.save()
            else:
                thread.published = False
                thread.creator = None
                thread.save()
        return HttpResponseRedirect(thread.get_absolute_url())
    else:
        form = ModelThreadForm()
    return render(request, 'perguntar.html', {
                               'questionform': form,
    })

我尝试过使用

    data : { 'csrftoken': '{{ csrf_token }}', username : $('#username-text').val(), password : $('#password-text').val() }, // data sent with the post request

而不是

        data : { 'X-CSRFToken': '{{ csrf_token }}', username : $('#username-text').val(), password : $('#password-text').val() }, // data sent with the post request

在main.js上删除sameOrigin函数。对这种行为都没有任何影响。

1 个答案:

答案 0 :(得分:0)

当我遇到csrf

的问题时,这对我很有帮助

http://chevalry.livejournal.com/206466.html

$.ajaxSetup({
     beforeSend: function(xhr, settings) {
         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;
         }
         if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
             // Only send the token to relative URLs i.e. locally.
             xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
         }
     }
});

您也可以使用装饰器禁用csrf @csrf_excempt 但这是另一种方法