简体   繁体   English

使用 ajax 发出 http 请求以获得基本授权和 cors

[英]Make a http request with ajax for basic authorization and cors

The config for my httpd server 111.111.111.111 (supposed).我的 httpd 服务器111.111.111.111 (假设)的配置。
Config for cors and basic auth in /etc/httpd/conf/httpd.conf ./etc/httpd/conf/httpd.conf配置 cors 和基本身份验证。

<Directory "/var/www/html">
    Options Indexes FollowSymLinks
    AllowOverride AuthConfig
    Require all granted
    Header always set Access-Control-Allow-Origin "*"
    Header always set Access-Control-Allow-Methods "POST, GET, PUT, DELETE, OPTIONS"
    Header always set Access-Control-Allow-Credentials "true"
    Header always set Access-Control-Allow-Headers "Authorization,DNT,User-Agent,Keep-Alive,Content-Type,accept,origin,X-Requested-With"
</Directory>

Make some more configs for basic authorization on my server 111.111.111.111 .在我的服务器111.111.111.111上为基本授权做一些更多的配置。

cd /var/www/html && vim .htaccess
AuthName "login"  
AuthType Basic  
AuthUserFile /var/www/html/passwd  
require user username 

Create password for username.为用户名创建密码。

htpasswd -c /var/www/html/passwd username

Reboot httpd with :使用以下命令重新启动 httpd:

systemctl restart httpd

The /var/www/html/remote.html on the server 111.111.111.111 .服务器111.111.111.111上的/var/www/html/remote.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="Access-Control-Allow-Origin" content="*" />
</head>
<body>
<p>it is a test </p>
</body>
</html>

Test it with username and passwd when to open 111.111.111.111\\remote.html?username=xxxx&password=xxxx in browser.用用户名和密码测试什么时候在浏览器中打开111.111.111.111\\remote.html?username=xxxx&password=xxxx

it is a test

Get the response header with curl.使用 curl 获取响应标头。

curl -u xxxx:xxxx -I  http://111.111.111.111/remote.html
HTTP/1.1 200 OK
Date: Thu, 06 Sep 2018 00:59:56 GMT
Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips PHP/5.4.16
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, PUT, DELETE, OPTIONS
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Authorization,X-PINGOTHER,DNT,User-Agent,Keep-Alive,Content-Type,accept,origin,X-Requested-With
Last-Modified: Wed, 05 Sep 2018 15:01:05 GMT
ETag: "f5-575210b30e3cb"
Accept-Ranges: bytes
Content-Length: 245
Content-Type: text/html; charset=UTF-8

Add a parameter OPTIONS in header .在 header 中添加参数OPTIONS

curl -X OPTIONS -i http://111.111.111.111/remote.html

HTTP/1.1 401 Unauthorized
Date: Thu, 06 Sep 2018 06:42:04 GMT
Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips PHP/5.4.16
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, PUT, DELETE, OPTIONS
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Authorization,X-PINGOTHER,DNT,User-Agent,Keep-Alive,Content-Type,accept,origin,X-Requested-With
WWW-Authenticate: Basic realm="please login"
Content-Length: 381
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>401 Unauthorized</title>
</head><body>
<h1>Unauthorized</h1>
<p>This server could not verify that you
are authorized to access the document
requested.  Either you supplied the wrong
credentials (e.g., bad password), or your
browser doesn't understand how to supply
the credentials required.</p>
</body></html>

Add OPTIONS and basic authorization in header.在标题中添加OPTIONS和基本授权。

curl -X OPTIONS -u xxxx:xxxxx  -i http://111.111.111.111/remote.html

HTTP/1.1 200 OK
Date: Thu, 06 Sep 2018 06:42:54 GMT
Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips PHP/5.4.16
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, PUT, DELETE, OPTIONS
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Authorization,X-PINGOTHER,DNT,User-Agent,Keep-Alive,Content-Type,accept,origin,X-Requested-With
Allow: POST,OPTIONS,GET,HEAD,TRACE
Content-Length: 0
Content-Type: text/html; charset=UTF-8

Ok, everything is good status.好的,一切都很好。
Let's try ajax's basic authorization.我们来试试ajax的基本授权。

The /var/www/html/test.html on my local apache.我本地 apache 上的/var/www/html/test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <script src="http://127.0.0.1/jquery-3.3.1.js"></script>
    <script>
    function Ajax( ) {
        var url = 'http://111.111.111.111/remote.html';
        $.ajax(url, {
            type:"get",
            dataType: 'html',
            withCredentials: true,
            username: "xxxx",
            password: "xxxx",
            success:function(response){
                mytext = $("#remote");
                mytext.append(response);
            },
            error: function (e) {
                alert("error");
            }    
        });
    };
    </script>

    <input type="button" value="show content" onclick="Ajax();">
    <p id="remote">the content on remote webpage</p>
</body>
</html>

To click show content button when to input 127.0.0.1/test.html ,i got the error:要在输入127.0.0.1/test.html时单击show content按钮,我收到错误消息:

GET http://111.111.111.111/remote.html 401 (Unauthorized)

在此处输入图片说明

I have given a detailed description based on httpd setting (centos7) and ajax and others related to the issue, please download my code and save it in your vps and local htdocs directory, replace ip with your real ip, reproduce the process.我已经根据httpd设置(centos7)和ajax等相关问题进行了详细说明,请下载我的代码并保存在你的vps和本地htdocs目录下,用你的真实ip替换ip,重现过程。
I beg you not to make any comments until you reproduce the process.我恳求您在重现该过程之前不要发表任何评论。
you may find what happened, maybe it is same as mine here.你可能会发现发生了什么,也许这里和我的一样。

Two important elements in the issue.问题中的两个重要因素。
1.httpd setting in the file /etc/httpd/conf/httpd.conf . 1.httpd 文件/etc/httpd/conf/httpd.conf设置。
2.ajax code 2.ajax代码
Which one is wrong?哪一个是错的?
How to fix it?如何解决?

I have some clue to solve the issue, thanks to @sideshowbarker.感谢@sideshowbarker,我有了一些解决问题的线索。

reason 原因

The problem turns into another one:问题变成了另一个:
How to configure the apache to not require authorization for OPTIONS requests?如何将 apache 配置为不需要 OPTIONS 请求的授权?
I have tried as Disable authentication for HTTP OPTIONS method (preflight request) say.我试过Disable authentication for HTTP OPTIONS method (preflight request)说。

Disable authentication for HTTP OPTIONS method (preflight request)e 禁用 HTTP OPTIONS 方法的身份验证(预检请求)e

<Directory "/var/www/html">
<LimitExcept OPTIONS>
  Require valid-user
</LimitExcept>
</Directory>

systemctl restart httpd ,failed. systemctl restart httpd ,失败。

If you console.log the error you will see a message saying:如果您console.log错误,您将看到一条消息:

Failed to load http://111.111.111.111/remote.html : The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include' .无法加载http://111.111.111.111/remote.html请求的凭据模式为 'include',响应中的'Access-Control-Allow-Origin'标头的值不能是通配符 '* ' Origin ' http://127.0.0.1/ ' is therefore not allowed access.因此不允许访问源“ http://127.0.0.1/ ”。 The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute. XMLHttpRequest发起的请求的凭证模式由withCredentials属性控制。

This is to protect against CSRF attacks .这是为了防止 CSRF 攻击

Eg If wildcard could be used in this case: Malicious- SiteA could access privileged resources without authorization on target- SiteB through browser-initiated ajax reqests , just because victim at some point provided crendentials for SiteB , while he was on trusted- SiteC .例如,如果在这种情况下可以使用通配符:Malicious- SiteA可以通过浏览器启动的 ajax reqests未经授权访问目标SiteB上的特权资源,只是因为受害者在某个时候为SiteB提供了凭据,而他在受信任的SiteC

So the solution is to just change Access-Control-Allow-Origin from "*" to " http://127.0.0.1 ", ( SiteC address in the example above)所以解决方案是将Access-Control-Allow-Origin从“*”更改为“ http://127.0.0.1 ”,(上例中的SiteC地址)


Now in order for curl -X OPTIONS -i http://111.111.111.111/remote.html to work while keeping active authentication for other methods, you need to add the following to .htaccess , or to httpd.conf :现在为了让curl -X OPTIONS -i http://111.111.111.111/remote.html在保持其他方法的主动身份验证的同时工作,您需要将以下内容添加到.htaccesshttpd.conf

<LimitExcept OPTIONS>
   AuthName "login"
   AuthType Basic
   AuthBasicProvider file
   AuthUserFile /var/www/cors-auth.passwd
   Require user username
 </LimitExcept>

EDIT:编辑:

LimitExcept OPTIONS is required if you need to prefill the username/password (as in your case), instead of expecting the browser to prompt a dialog .如果您需要预先填写用户名/密码(如您的情况),而不是期望浏览器提示对话框,则需要LimitExcept OPTIONS But to make it work on all browsers (chrome/ff/edge), I had to replace this:但是为了让它在所有浏览器(chrome/ff/edge)上都能工作,我不得不替换这个:

        withCredentials: true,
        username: "xxxx",
        password: "xxxx",

with this:有了这个:

      beforeSend: function (xhr){ 
           xhr.setRequestHeader('Authorization', "Basic " + btoa("xxxx:xxxx")); 
       },

try putting localhost instead of ' http://111.111.111.111/remote.html '尝试放置 localhost 而不是 ' http://111.111.111.111/remote.html '

' http://localhost/remote.html .It should work .It may be your public ip address issue where port 80 is not open. ' http://localhost/remote.html 。它应该可以工作。这可能是您的公共 IP 地址问题,其中端口 80 未打开。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM