需要身份验证时,带有 JSON 中断的跨源 AJAX 请求

Posted

技术标签:

【中文标题】需要身份验证时,带有 JSON 中断的跨源 AJAX 请求【英文标题】:Cross origin AJAX request with JSON breaks when authentication is required 【发布时间】:2015-04-27 23:51:06 【问题描述】:

我正在尝试对不同站点上的 php 文件进行 AJAX 调用:

$.ajax(                                      
    type: "GET",
    dataType: "json",
    url: 'http://user:password@www.myurl.com/myphpfile.php',
    data: 
        records: JSON.stringify(workingarray),
        account: account,
    ,

    complete: function(response) 
        var parsedresponse = $.parseJSON(JSON.stringify(response)).responseText.split("<br>");
        otherFunction(parsedresponse);
    
);

我的 PHP 文件:

<?php
header('Access-Control-Allow-Origin: *');
header('content-type: application/json; charset=utf-8');

$records = json_decode($_GET['records']);
$account = $_GET['account'];

 .....[LOGIN AND SQL QUERY].....

$result = $conn->query($sql);

while ($row = $result->fetch_assoc()) 
    echo json_encode($row['Some columns']."<br>", JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    

$conn->close();
?>

这一切都很好,直到我注意到我实际上并没有打开身份验证。一旦我这样做了,整个事情就崩溃了,我总是收到以下错误:

XMLHttpRequest 无法加载 http://user:password@www.myurl.com/myphpfile.php (...) 。不 请求中存在“Access-Control-Allow-Origin”标头 资源。因此不允许使用原点“http://originurl.co.uk” 使用权。响应的 HTTP 状态代码为 401。

正如您将在我的 PHP 代码中看到的那样,存在一个标头。我还尝试将以下 2 行添加到我的 .htaccess 中:

Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Credentials true

效果令人沮丧,也就是说,没有任何效果。

我已尝试将数据类型转换为 JSONP,但我不确定如何执行此操作...我尝试了以下更改:

$.ajax(                                      
    type: "GET",
    dataType: "jsonp",
    url: 'http://user:password@www.myurl.com/myphpfile.php?callback=?',
    data: 
        records: JSON.stringify(workingarray),
        account: account,
    ,

    complete: function(response) 
        var parsedresponse = $.parseJSON(JSON.stringify(response)).responseText.split("<br>");
        otherFunction(parsedresponse);
    
);

我的 PHP 文件:

<?php
header('Access-Control-Allow-Origin: *');
header('content-type: application/jsonp; charset=utf-8');

...

while ($row = $result->fetch_assoc()) 
    echo $_GET['callback'] . "(" . json_encode($row['Some columns']."<br>", JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . ")";
    

$conn->close();
?>

据我所知,这不会导致控制台出现错误,但我在响应中唯一能理解的是:

状态:200

statusText:“加载”

(我在complete: 函数中添加了一个console.log(parsedresponse) 行用于调试目的,但我必须承认我并不完全确定如何解释我所看到的大部分内容。)

任何帮助或建议将不胜感激,因为这让我很沮丧。

【问题讨论】:

可能是 OPTION 请求失败,而不是实际的 GET。检查飞行前是否返回 401 或 GET。 感谢您的回复,我很抱歉,但我不确定如何执行您的建议。 当 CORS 发生时,发送 2 个单独的请求,(OPTIONS 和 GET)不仅仅是一个。(只有正常的 GET)。使用嗅探器查看哪个失败并带有 HTTP 401 响应代码。 (你可以使用 Fiddler 或类似的东西来嗅探这个)。 用户名和密码在不加密的情况下从客户端传输到服务器并传入 url 是非常安全的!!! 马文,谢谢你,今天下午我会调查的。 Halayem,我知道基本身份验证在安全方面并不理想,但受密码保护的文件夹中没有特别敏感的信息。尽管如此,我还是更愿意使用更安全的方法。你有什么建议吗?使用 HTTPS 会有帮助吗?虽然如果我这样做,我肯定需要走 JSONP 路线,因为来源不是 HTTPS。我也考虑过取消保护文件夹并将数据库登录信息作为 AJAX 调用的一部分传递,但我不确定这是否更安全...... 【参考方案1】:

我相信我已经解决了这个问题 - 我还没有完全重写应用程序,但我能够拨打电话并得到响应,所以从现在开始一切都应该一帆风顺(著名的遗言,哈哈)。

无论如何,我所做的更改如下 - 我首先在 AJAX 调用中将 complete 切换为 success

$.ajax(                                      
    type: "GET",
    dataType: "jsonp",
    url: 'https://user:password@www.myurl.com/myphpfile.php?callback=?',
    data: 
        records: JSON.stringify(workingarray),
        account: account,
    ,
    success: function(response) 
        console.log(response);
        otherFunction(response);
    
);

然后,我认为这可能是主要问题,我不得不重写这部分 PHP 文件...

$result = $conn->query($sql);

while ($row = $result->fetch_assoc()) 
    echo json_encode($row['Some columns']."<br>", JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    

...变成:

$result = $conn->query($sql);
$rows = array();

while ($row = $result->fetch_assoc()) 
        $rows[] = array('data' => $row['Some columns']);
    

echo $_GET['callback'] . "(" . json_encode($rows, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . ")";

...显然(回想起来)我以前的方法是返回多个具有相同名称的函数。

我还将请求 URL 更改为 https,我认为这对于预期用途来说应该足够安全。

无论如何希望有人觉得我的经验有用。

【讨论】:

以上是关于需要身份验证时,带有 JSON 中断的跨源 AJAX 请求的主要内容,如果未能解决你的问题,请参考以下文章

javascript Ajax调用(带有无聊的跨源问题)

Docker 容器的跨源错误

在已部署的应用程序上播放来自 s3 的文件时的跨源资源策略问题

Devise 的 HTTP 身份验证中断了常规注销

带有rails 3应用程序的ios json身份验证

使用 CORS 过滤器的跨源请求