【问题标题】:JQuery Ajax calls with HTTP Basic Authentication使用 HTTP 基本身份验证的 JQuery Ajax 调用
【发布时间】:2012-03-30 07:52:30
【问题描述】:

我有一个基于 REST 的服务器,我正在尝试使用 JQuery 与之通信。 XML 和 JSON 都可以作为响应格式,所以我使用的是 JSON。

连接都是 SSL,所以 HTTP 基本身份验证一直是我们选择的授权方法,并且我们在其他前端(原始 Javascript、Silverlight 等)方面没有问题

现在我正在尝试将一些东西与 JQuery 放在一起,但在使用 HTTP 基本身份验证时遇到了无穷无尽的问题。

我已经浏览了许多以前的问题,其中大多数问题的解决方案似乎并没有真正起作用,或者将整个问题归咎于跨源访问,我已经在基本的 Javascript 测试中克服了这些问题。响应始终提供 Access-Control-Allow-Origin 设置为请求中提供的 Origin 标头,这可以在我的测试响应中看到。

在基本的 javascript 中,整个调用非常简单地通过以下方式完成:

req.open('GET', 'https://researchdev-vm:8111/card', true, 'test', 'testpassword');

JQuery 在这方面的尝试是相当标准的:

        $.ajax({
        username: 'test',
        password: 'testpassword',
        url: 'https://researchdev-vm:8111/card',
        type: 'GET',
        dataType: 'json',
        crossDomain: true,
        /*data: { username: 'test', password: 'testpassword' },*/
        beforeSend: function(xhr){
            xhr.setRequestHeader("Authorization",
                //"Basic " + encodeBase64(username + ":" + password));
                "Basic AAAAAAAAAAAAAAAAAAA=");
        },
        sucess: function(result) {
            out('done');
        }
    });

实际上似乎可以提供身份验证的唯一方法是将 Base64 编码数据直接插入 beforeSend() 函数中。如果这不包括在内,则没有任何进展。用户名和密码属性似乎完全被忽略了。

通过提供beforeSend() 行为,GET 调用会获得包含数据的肯定响应。但是,因为这是一个跨站点调用,OPTIONS 调用在 GET 调用之前执行并且总是失败,因为它没有使用beforeSend(),因此由于身份验证失败而得到 401 响应。

有没有更好的方法来完成一个非常微不足道的调用? OPTIONS 请求不使用beforeSend() 函数处理这一事实是否应该被视为错误?有没有办法完全禁用 OPTIONS 检查?不可能使这个调用不是跨站点的,因为 Javascript 似乎甚至将同一台机器上的不同端口号视为“跨站点”。

【问题讨论】:

  • 您不必拥有发送前和用户名/密码字段。我会从您的 $.ajax 函数中删除用户名/密码字段。

标签: javascript jquery ajax basic-authentication http-authentication


【解决方案1】:

这个问题可能已经过了它的有效期,但我在使用 Jquery 做同样的事情时遇到了同样的问题。

用户名和密码属性似乎不像通常完成 HTTP 基本身份验证那样对用户名/密码进行 base64 编码。

查看以下请求(为简洁起见),首先使用JQuery AJAX方法中的“用户名”和“密码”参数:

Request URL:http://testuser%40omnisoft.com:testuser@localhost:60023/Account
Request Method:GET
Accept:application/json, text/javascript, */*; q=0.01
Host:localhost:60023

现在使用 beforeSend 方法:

Request URL:http://localhost:60023/Account
Request Method:GET
Accept:application/json, text/javascript, */*; q=0.01
Authorization:Basic dXNlcm5hbWU6cGFzc3dvcmQ=
Host:localhost:60023

请注意,第一种方法在请求中不包含“授权”标头,而是在目标 URL 前添加前缀。我不是 HTTP 基本身份验证方面的专家,但这表明前者不是正确的实现,因此会失败(或者至少它与我自己的服务器实现有关)。

至于您使用 JSONP 的 OPTIONS 请求 - 您可以尝试在您的 URL 中使用 ?callback=? 而不是使用 crossdomain 选项,只是为了明确。

【讨论】:

    【解决方案2】:

    对于遇到此问题的任何人,我已经解决了使用 Apache 拦截 OPTIONS 请求并仅将 GET 和 POST 转发到后端的问题。

    此解决方案独立于应用服务器,因此也适用于 PHP 和 Java:

    <VirtualHost *:80>
    
        # ServerName and other configuration...
    
    
        # CORS
        Header set Access-Control-Allow-Origin "*"
        Header set Access-Control-Allow-Methods "OPTIONS, GET, PUT, POST" 
        Header set Access-Control-Allow-Headers "Authorization"
    
        # Intercept OPTIONS calls
        RewriteEngine On
        RewriteCond %{REQUEST_METHOD} ^(OPTIONS)$
        RewriteRule .* - [L]
    
        # Backend, adapt this line to fit your needs
        RewriteRule /(.*) ajp://localhost:8010/$1 [L,P]
    
    </VirtualHost>
    

    问候, 毛里齐奥

    【讨论】:

    • 对于正确的 REST 实现,您可能还需要包含 PUT 方法。
    【解决方案3】:

    这里有一些东西可以作为 AJAX 调用的传递身份验证。这依赖于NTLM 在将执行 javascript 的页面上进行身份验证。也许这会对你有所帮助:

    PHP 代码:

    <?php 
    $headers = apache_request_headers();
    if (isset($headers['Authorization'])) 
       echo "<script>var auth = " . $headers['Authorization'] . "</script>";
    unset($headers);
    ?>
    

    使用 jQuery 你会这样使用它:

    $.ajax({
            type: 'POST',
            url: './somePage.php',
            data: {"test":true},
            dataType: 'json',
            success: function(data) {
                console.log(data.username);
            },
            beforeSend : function(req) {
                req.setRequestHeader('Authorization', auth); // <<<<----- USED HERE
            },
    });
    

    对于标准 XMLHttpRequest:

    var xml = new XMLHttpRequest();
    xml.open('GET', './somePage.php', true);
    xml.setRequestHeader('Authorization', auth); // <<<<----- USED HERE
    xml.send();
    

    【讨论】:

    • 如果您提供了一个“auth”变量的示例,将会很有帮助。我想这是一个具有用户和密码属性的对象,但最好明确说明
    • @TKoL OP 提供了 auth 值的示例。本质上是:"Basic " + encodeBase64(username + ":" + password));
    猜你喜欢
    • 1970-01-01
    • 2016-01-01
    • 2011-07-27
    • 1970-01-01
    • 2016-07-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多