最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Make a http request with ajax for basic authorization and cors - Stack Overflow

programmeradmin4浏览0评论

The config for my httpd server 111.111.111.111 (supposed).
Config for cors and basic auth in /etc/httpd/conf/httpd.conf.

<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.

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 :

systemctl restart httpd

The /var/www/html/remote.html on the server 111.111.111.111 .

<!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.

it is a test

Get the response header with 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 .

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.

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.

The /var/www/html/test.html on my local apache.

<!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:

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.
I beg you not to make any ments 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.
2.ajax code
Which one is wrong?
How to fix it?

I have some clue to solve the issue, thanks to @sideshowbarker.

reason

The problem turns into another one:
How to configure the apache to not require authorization for OPTIONS requests?
I have tried as Disable authentication for HTTP OPTIONS method (preflight request) say.

Disable authentication for HTTP OPTIONS method (preflight request)e

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

systemctl restart httpd,failed.

The config for my httpd server 111.111.111.111 (supposed).
Config for cors and basic auth in /etc/httpd/conf/httpd.conf.

<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.

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 :

systemctl restart httpd

The /var/www/html/remote.html on the server 111.111.111.111 .

<!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.

it is a test

Get the response header with 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 .

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.

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.

The /var/www/html/test.html on my local apache.

<!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:

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.
I beg you not to make any ments 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.
2.ajax code
Which one is wrong?
How to fix it?

I have some clue to solve the issue, thanks to @sideshowbarker.

reason

The problem turns into another one:
How to configure the apache to not require authorization for OPTIONS requests?
I have tried as Disable authentication for HTTP OPTIONS method (preflight request) say.

Disable authentication for HTTP OPTIONS method (preflight request)e

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

systemctl restart httpd,failed.

Share Improve this question edited Sep 11, 2018 at 20:18 Knu 15.2k6 gold badges59 silver badges92 bronze badges asked Sep 1, 2018 at 7:41 showkeyshowkey 31851 gold badges161 silver badges323 bronze badges 6
  • What happens when you try curl -X OPTIONS -i http://111.111.111.111/remote.html? – sideshowbarker Commented Sep 6, 2018 at 4:05
  • Please view my revised post,and do as i say in your vps. – showkey Commented Sep 6, 2018 at 6:48
  • 5 The problem with adding the credentials to the OPTIONS request is, browsers don’t add them when they do CORS preflights. See fetch.spec.whatwg/#ref-for-credentials%E2%91%A5 (“a CORS-preflight request never includes credentials”). Instead for the preflight, browsers send an OPTIONS request without any Authorization header. That means the server receiving the request must be configured to accept OPTIONS requests without requiring authentication, & must response to those unauthenticated OPTIONS requests with a 200 OK. Otherwise the preflight fails. That’s the problem you’ve run into – sideshowbarker Commented Sep 6, 2018 at 7:17
  • See also the answer at stackoverflow./questions/45405983/… – sideshowbarker Commented Sep 6, 2018 at 7:18
  • 2 I guess it's not really a direct answer to your question but you really shouldn't send a plaintext password over HTTP as a GET request. – Michael Curry Commented Sep 10, 2018 at 17:00
 |  Show 1 more ment

2 Answers 2

Reset to default 3

If you console.log the error you will see a message saying:

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'. Origin 'http://127.0.0.1/' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

This is to protect against CSRF attacks.

E.g. 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.

So the solution is to just change Access-Control-Allow-Origin from "*" to "http://127.0.0.1", (SiteC address in the example above)


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:

<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. But to make it work on all browsers (chrome/ff/edge), I had to replace this:

        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'

'http://localhost/remote.html .It should work .It may be your public ip address issue where port 80 is not open.

发布评论

评论列表(0)

  1. 暂无评论