为什么浏览器在经过身份验证的XMLHttpRequest之后不重用授权头?

Syl*_*ain 40 html javascript basic-authentication angularjs single-page-application

我正在使用Angular开发单页应用程序.后端公开需要基本身份验证的REST服务.获取index.html或任何脚本不需要身份验证.

我有一个奇怪的情况:我的观点的人有一个<img>,其中src是一个REST API需要验证的URL.它<img>由浏览器处理,我没有机会为它所做的GET请求设置授权标头.这会导致浏览器提示输入凭据.

我尝试通过这样做解决这个问题:

  1. img src在源空
  2. 在"文档就绪"中,使用Authorization标头创建XMLHttpRequest一个service(/api/login),以便进行身份验证.
  3. 完成该调用后,设置该img src属性,认为到那时,浏览器会知道在后续请求中包含Authorization标头...

......但事实并非如此.图像请求没有标题.如果我输入凭据,则页面上的所有其他图像都是正确的.(我也试过和Angular的ng-src但是产生了相同的结果)

我有两个问题:

  1. 为什么浏览器(IE10)在成功后的所有请求中都没有包含标题XMLHttpRequest
  2. 我该怎么做才能解决这个问题?

@bergi询问了请求的详细信息.他们来了.

请求/ api /登录

GET https://myserver/dev30281_WebServices/api/login HTTP/1.1
Accept: */*
Authorization: Basic <header here>
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.2; WOW64; Trident/6.0; .NET4.0E; .NET4.0C; .NET CLR 3.5.30729; .NET CLR 2.0.50727; .NET CLR 3.0.30729)
Connection: Keep-Alive
Run Code Online (Sandbox Code Playgroud)

响应(/ api/login)

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 4
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Fri, 20 Dec 2013 14:44:52 GMT
Run Code Online (Sandbox Code Playgroud)

要求/ user/picture/2218:

GET https://myserver/dev30281_WebServices/api/user/picture/2218 HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.2; WOW64; Trident/6.0; .NET4.0E; .NET4.0C; .NET CLR 3.5.30729; .NET CLR 2.0.50727; .NET CLR 3.0.30729)
Connection: Keep-Alive
Run Code Online (Sandbox Code Playgroud)

然后Web浏览器会提示输入凭据.如果我输入它们,我得到这个回复:

HTTP/1.1 200 OK
Cache-Control: public, max-age=60
Content-Length: 3119
Content-Type: image/png
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Fri, 20 Dec 2013 14:50:17 GMT
Run Code Online (Sandbox Code Playgroud)

Com*_*eek 24

基本的想法

通过JavaScript加载图像并将其显示在网站上.优点是身份验证凭据永远不会进入HTML.他们会在JavaScript方面抗拒.

第1步:通过JS加载图像数据

这是基本的AJAX功能(另请参阅XMLHttpRequest::open(method, uri, async, user, pw)):

var xhr = new XMLHttpRequest();
xhr.open("GET", "your-server-path-to-image", true, "username", "password");

xhr.onload = function(evt) {
  if (this.status == 200) {
    // ...
  }
};
Run Code Online (Sandbox Code Playgroud)

第2步:格式化数据

现在,我们如何显示图像数据?使用HTML时,通常会src为图像元素的属性分配URI .我们可以在这里应用相同的原则,除了我们使用数据URI而不是"普通" http(s)://派生的事实.

xhr.onload = function(evt) {
  if (this.status == 200) {
    var b64 = utf8_to_b64(this.responseText);
    var dataUri = 'data:image/png;base64,' + b64; // Assuming a PNG image

    myImgElement.src = dataUri;
  }
};

// From MDN:
// https://developer.mozilla.org/en-US/docs/Web/API/window.btoa
function utf8_to_b64( str ) {
    return window.btoa(unescape(encodeURIComponent( str )));
}
Run Code Online (Sandbox Code Playgroud)

帆布

还有另一个选项,包括在<canvas>字段中绘制加载的数据.这样,用户将无法右键单击图像(画布所在的区域),而不是<img>用户在查看图像属性面板时将看到长数据URI的数据URI.


flu*_*lup 8

谷歌驱动器上传器使用角度js创建.它的作者遇到了类似的问题.这些图标托管在不同的域上,并将它们视为img src=违反了CSP.因此,和你一样,他们不得不使用XHR获取图标图像,然后以某种方式设法将它们放入img标签中.

他们描述了他们如何解决它.在使用XHR获取图像后,他们将其写入HTML5本地文件系统.他们把它的URL中的本地文件系统中imgsrc使用属性ng-src指令.

$http.get(doc.icon, {responseType: 'blob'}).success(function(blob) {
  console.log('Fetched icon via XHR');
  blob.name = doc.iconFilename; // Add icon filename to blob.
  writeFile(blob); // Write is async, but that's ok.
  doc.icon = window.URL.createObjectURL(blob);
  ...
}
Run Code Online (Sandbox Code Playgroud)

至于为什么,我不知道.我假设创建用于检索图像的会话令牌是不可能的?我希望Cookie标头会被发送?这是跨来源请求吗?在这种情况下,您是否设置了withCredentials属性?这可能是P3P的事吗?