Django CSRF 令牌错误或缺少 Ajax POST 请求

Posted

技术标签:

【中文标题】Django CSRF 令牌错误或缺少 Ajax POST 请求【英文标题】:Django CSRF Token error or missing with Ajax POST request 【发布时间】:2021-12-28 04:05:01 【问题描述】:

我正在尝试使用 Django 框架将 ajax 集成到 Web 应用程序中。但是,我很难尝试进行简单的 ajax 调用来工作。

我想使用表单(用户输入数据库凭据)建立数据库连接,调用 API,然后返回输出(无论成功与否)。

这是我用于处理 API 的 views.py

# -- START from HERE !
class TestConnectionAPI(views.APIView):
    '''
    Test DB Connection from TARGET DB
    '''  
    def post(self, request):
        dbs = (request.data['host'],
                request.data['port'],
                request.data['dbname'],
                request.data['user'],
                request.data['password'],
                request.data['schema_name'])

        try:
            x = dc.DbConnection(*dbs)
            x.create_conn()
            data = x.check_conn()           
            
            result = 
                'message' : 'Success',
                'server' : f'Connection established from data',
                'results':
                    'host':dbs[0],
                    'port':dbs[1],
                    'dbname':dbs[2]
                    ,
            
            return Response(result, status=status.HTTP_200_OK)
        except Exception as e:
            return Response('Message':str(e), status=status.HTTP_400_BAD_REQUEST)

这是我的 connection.html 显示表单(完整代码:here):

...
<form method="post">
                                    <div class="modal-body">
                                        <div class="form-group">
                                            <label for="host">Hostname</label>
                                            <input type="text" class="form-control" id="host" name="host" aria-describedby="host">
                                        </div>
                                        <div class="form-group">
                                            <label for="port">Port</label>
                                            <input type="number" class="form-control" id="port" name="port" placeholder="e.g., 5432">
                                        </div>
                                        <div class="form-group">
                                            <label for="database">Database name</label>
                                            <input type="text" class="form-control" id="dbname" name="dbname" placeholder="Enter database name">
                                        </div>
                                        <div class="form-group">
                                            <label for="username">Username</label>
                                            <input type="text" class="form-control" id="user" name="user" placeholder="Enter username">
                                        </div>
                                        <div class="form-group">
                                            <label for="password">Password</label>
                                            <input type="password" class="form-control" id="password" name="password">
                                        </div>
                                        <div class="form-group">
                                            <label for="schema">Schema</label>
                                            <input type="text" class="form-control" id="schema_name" name="schema_name">
                                        </div>
                                    </div>
                                    <div class="modal-footer border-top-0 d-flex justify-content-center">
                                        <a href="#form2" class="btn btn-primary" data-toggle="modal" type="submit" id="btnSubmit">Test</a>
                                        <button type="submit" class="btn btn-success">Save</button>
                                    </div>
                                </form>
...

还有,这是用于调用 API(POST 请求)的 AJAX 函数

$('#btnSubmit').click(function () 

        let _host = $('#host').val();
        let _port = $('#port').val();
        let _dbname = $('#dbname').val();
        let _user = $('#user').val();
        let _password = $('#password').val();
        let _schema_name = $('#schema_name').val();

        var $crf_token = $('[name="csrfmiddlewaretoken"]').attr('value');

        $.ajax(
            type: 'POST',
            dataType: 'JSON',
            headers:"X-CSRFToken": $crf_token,
            data:
                "host" : _host,
                "port" : _port,
                "dbname" : _dbname,
                "user" : _user,
                "password" : _password,
                "schema_name": _schema_name,
            ,

            url:"http://127.0.0.1:8000/api/v1/test/",
            error: function (xhr, status, error) 
                var err_msg = ''
                for (var prop in xhr.responseJSON) 
                    err_msg += prop + ': ' + xhr.responseJSON[prop] + '\n';
                

                alert(err_msg);
                ,
            
            success: function (result) 
                console.log(result);
            
        );
    );

这是我的错误

但是,我很难修复错误。我尝试关注 *** 论坛中的一些讨论,但仍然出现此错误。该错误与 CSRF 令牌有关,我很难按照 Django 文档进行操作。

至少我想在控制台日志上显示这个 API 响应。


    "message": "Success",
    "server": "Connection established from ('PostgreSQL 12.7, compiled by Visual C++ build 1914, 64-bit',)",
    "results": 
        "host": "localhost",
        "port": 5432,
        "dbname": "dvdrental"
    

Added-1:POST 请求标头

你能帮我解决这个问题吗?谢谢。

【问题讨论】:

使用浏览器检查器检查 POST 请求。它是否在X-CSRFToken 标头中发送正确的值? @Selcuk,对不起,谢谢您的回复。我使用浏览器检查器进行了检查。不幸的是,我找不到X-CSRFToken。这也是另一个问题吗?我将结果添加到问题中。 看起来这是你的问题。我看到一些请求将发送至test,而其他请求将发送至test/。是否有从一个重定向到另一个?这可能会导致浏览器丢弃您的标题。 @Selcuk,是的,我的views.py 文件中有从一页到另一页的重定向。但是,我通过向 AJAX 脚本添加一些函数(即 Cookie)解决了我的错误。幸运的是,我可以看到 X-CSRF Token 标头并从 API 获取数据。非常感谢。 【参考方案1】:

这是我为解决问题所做的。我在主函数中添加了一些脚本。通过使用此脚本,我的错误消息:csrf token invalid or missing 得到解决。

已编辑脚本:

<script>
    // DB Connection GET method
    function BindConnection()
        $.ajax(
            type:"GET",
            dataType: "JSON",
            url: "http://127.0.0.1:8000/api/v1/test",
            
            success: function(data)
                console.log("BindConnection output:",data);
                
                var str = "";

                for (var key in data)
                    // console.log(data[key]);
                    str += "<tr>" +
                        "<td>" + data[key] + "</td>"
                    "</tr>"
                
                $("#divBody").html(str);
            
        );
    

    // DB Connection POST method
    $('#btnSubmit').click(function () 

        let _host = $('#host').val();
        let _port = $('#port').val();
        let _dbname = $('#dbname').val();
        let _user = $('#user').val();
        let _password = $('#password').val();
        let _schema_name = $('#schema_name').val();

        // added function
        function Cookies(name) 
            var cookieValue = null;
            if (document.cookie && document.cookie !== '') 
                var cookies = document.cookie.split(';');
                for (var i = 0; i < cookies.length; i++) 
                    var cookie = cookies[i].trim();
                    // 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 = Cookies('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);
                
            
        );
        // --- end of added function

        $.ajax(
            type: 'POST',
            dataType: 'JSON',
            data:
                "host" : _host,
                "port" : _port,
                "dbname" : _dbname,
                "user" : _user,
                "password" : _password,
                "schema_name": _schema_name,
            ,
            url:"http://127.0.0.1:8000/api/v1/test/",
            error: function (xhr, status, error) 
                var err_msg = ''
                
                for (var prop in xhr.responseJSON) 
                    err_msg += prop + ': ' + xhr.responseJSON[prop] + '\n';
                

                // alert(err_msg);
                $("#divMessage").html(err_msg)
                ,
            
            success: function (result) 
                var str = "";
                
                for (var key in result)
                    str += "<p>" + result[key] + "</p>"
                
                $("#divMessage").html(str)
                console.log(str)
            
        );
    );
</script>

【讨论】:

以上是关于Django CSRF 令牌错误或缺少 Ajax POST 请求的主要内容,如果未能解决你的问题,请参考以下文章

在 Django 中的 ajax POST 期间被禁止(CSRF 令牌丢失或不正确。)

禁止(CSRF 令牌丢失或不正确。)Django

禁止(CSRF 令牌丢失或不正确)Django 错误

Django 1.9 AJAX 表单 CSRF 令牌 403 错误 - “未设置 CSRF cookie”

Django - 在同一个模板(ajax 和表单)中处理多个 CSRF 令牌禁止(CSRF 令牌丢失或不正确。)

注册表单不起作用(CSRF 令牌丢失或不正确。) django