hls.js CORS 使用 AWS Cloudfront 的 Cookie 问题

Posted

技术标签:

【中文标题】hls.js CORS 使用 AWS Cloudfront 的 Cookie 问题【英文标题】:hls.js CORS using AWS Cloudfront issues with Cookies 【发布时间】:2017-12-11 04:07:02 【问题描述】:

我正在尝试使用 Cloudfront HLS 功能设置视频流,但我无法让 Hls.js 在请求中发送我的凭据 cookie。

我已经将 Cloudfront 配置为转发 cookie 和转发访问控制标头。我还设置了我的 S3 CORS 策略以包括 GET、HEAD。

我遇到的问题是,即使我设置了 xhr.withCredentials=true 并且 cookie 是在会话中定义的,但当我使用 chrome 控制台查看请求时,我可以看到 HLS 请求有没有饼干。结果,我收到来自云端的错误响应,说我需要包含凭据 cookie。

代码: 首先,我向我的服务器发出 ajax 请求以生成 cookie。服务器返回三个 Set-Cookies 标头,作为会话 cookie 存储在浏览器中:

$.ajax(

type: 'GET',
url: 'http://subdomain.mydomain.com:8080/service-
webapp/rest/resourceurl/cookies/98400738-a415-4e32-898c-9592d48d1ad7',
success: function (data) 
        playMyVideo();
,
headers:  "Authorization": 'Bearer XXXXXX' 
);

一旦存储了 cookie,就会调用测试函数来使用 HLS.js 播放我的视频:

function test()
  if (Hls.isSupported()) 
  var video = document.getElementById('video');
  var config = 
    debug: true,
    xhrSetup: function (xhr,url) 
        xhr.withCredentials = true; // do send cookie
    xhr.setRequestHeader("Access-Control-Allow-Headers","Content-Type, Accept, X-Requested-With");
        xhr.setRequestHeader("Access-Control-Allow-Origin","http://sybdomain.domain.com:8080");
    xhr.setRequestHeader("Access-Control-Allow-Credentials","true");
    
  ;
  var hls = new Hls(config);
  // bind them together
  hls.attachMedia(video);
  hls.on(Hls.Events.MEDIA_ATTACHED, function () 
    console.log("video and hls.js are now bound together !");
    hls.loadSource("http://cloudfrontDomain.net/small.m3u8");
    hls.on(Hls.Events.MANIFEST_PARSED, function (event, data) 
      console.log("manifest loaded, found " + data.levels.length + " quality level");
    );
  );

video.play();

正如您在下面看到的 HLS OPTIONS 和 GET 请求不设置会话 cookie:

HLS 选项请求:

OPTIONS /hls/98400738-a415-4e32-898c-9592d48d1ad7/small.m3u8 HTTP/1.1
Host: cloudfrontDomain.net
Connection: keep-alive
Access-Control-Request-Method: GET
Origin: subdomain.mydomain.com:8080
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/59.0.3071.104 Safari/537.36
Access-Control-Request-Headers: access-control-allow-credentials,access-control-allow-headers,access-control-allow-origin
Accept: */*
Referer: http://subdomain.mydomain.com:8080/play.html
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8,es;q=0.6

CloudFront 响应:

HTTP/1.1 200 OK
Content-Length: 0
Connection: keep-alive
Date: Fri, 07 Jul 2017 00:16:31 GMT
Access-Control-Allow-Origin: http://subdomain.mydomain.com:8080
Access-Control-Allow-Methods: GET, HEAD
Access-Control-Allow-Headers: access-control-allow-credentials, access-control-allow-headers, access-control-allow-origin
Access-Control-Max-Age: 3000
Access-Control-Allow-Credentials: true
Server: AmazonS3
Vary: Origin,Access-Control-Request-Headers,Access-Control-Request-Method
Age: 845
X-Cache: Hit from cloudfront
Via: 1.1 cloudfrontDomain.net (CloudFront)
X-Amz-Cf-Id: XXXXXX

HLS 后续 GET 请求缺少 cookie:

GET /hls/98400738-a415-4e32-898c-9592d48d1ad7/small.m3u8 HTTP/1.1
Host: cloudfrontDomain.net
Connection: keep-alive
Origin: http://subdomain.mydomain.com:8080
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36
Access-Control-Allow-Origin: http://subdomain.mydomain.com:8080
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Content-Type, Accept, X-Requested-With
Accept: */*
Referer: http://subdomain.mydomain.com:8080/play.html
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8,es;q=0.6

我花了 4 天时间试图弄清楚这一点。我做了很多研究,但我就是想不出解决办法。我是 CORS 的新手,所以也许我不了解某些原则。我认为如果 cookie 存储在会话中,如果您使用凭据启用 xhr,它们会被设置,但似乎并非如此。

我注意到的另一件事是 HLS.js 生成的 GET 请求没有设置任何 xmlhttprequest 标头。

感谢您的帮助:)

【问题讨论】:

来自 example.com 页面的 XHR 请求向 example.net 发送带有凭据的跨域请求,将发送之前 由 example.net 返回的 cookie,而不是example.com 返回的 cookie。 所以我在这里面临两难境地。我的 web 服务接口与亚马逊 aws 生成 cookie。问题是 web 服务在不同的域中运行。这意味着除非云端域返回 set-cookie 标头,否则我无法将任何 cookie 传递给我的 CORS 请求?我认为云前端不支持根据预设策略生成 cookie 作为响应的一部分...有什么想法或建议吗? 在 CloudFront 中创建第二个源,将 Web 服务作为源主机名,并创建一个缓存行为,并将服务路由到该新源的路径。获取 cookie 的请求发送到 CloudFront,后者将其发送到源以获取 cookie,并且带有 cookie 的响应通过 CloudFront 返回并且它们设置在正确的域上。这原则上是可行的。它适用于您的服务吗? 计划 B。创建 sub.subdomain.example.com,指向 CloudFront。使用domain=.subdomain.example.comsubdomain.example.com 设置cookie,注意前导点。当您向 sub.subdomain.example.com 发送请求时,这些 cookie 应该可以工作。 谢谢!计划 B 的工作方式是现在发送 cookie。但是现在 CloudFront 只是拒绝了来自我的新 sub.subdomain.example.com AccessDenied Access denied 的任何请求我检查了我的 s3 存储桶并将其设置为允许 http://*https://* 【参考方案1】:

对于可能仅在 Chrome for android 上遇到此问题的任何人,我们的问题是浏览器正在缓存 m3u8 文件并给出相同的 CORS 错误。解决方案是将时间戳参数附加到文件 url 的查询字符串:

var config = 
  xhrSetup: function (xhr, url) 
    xhr.withCredentials = true; // do send cookies
    url = url + '?t=' + new Date().getTime();
    xhr.open('GET', url, true);
  
;
var hls = new Hls(config);

【讨论】:

【参考方案2】:

我终于可以让它工作了。感谢迈克尔的帮助!事实证明,这是不了解 CORS 原则如何工作和正确配置 aws 服务的混合体。主要问题是通过使用 cloudfront 为您的 web 服务和 s3 存储桶提供服务来避免跨域请求。我想补充的一个重要说明是,您在 aws 中所做的任何更改都必须等待它传播。作为一个新的 aws 开发人员,我不知道这一点,并且对做出没有效果的更改感到非常沮丧。这是解决方案:

1) 创建您的 S3 存储桶。

2) 创建 Cloudfront 分发版。

3) 在分发集中设置为您的 Web 服务域的默认来源。

4) 添加第二个来源并在分发中添加行为以将所有 .m3u8 和 .ts 文件转发到您的 S3 存储桶。

5) 添加存储桶来源时,请确保标记限制访问并更新存储桶策略复选框。

6) 在您的存储桶分配行为中,确保您转发所有白名单标头和 cookie。这都可以在 aws 控制台中设置。

7) 如果您在服务中使用不同的端口,请确保在分发版中也设置这些端口。

8) 转到您的 S3 存储桶设置并将 CORS 配置更新为以下内容:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>HEAD</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration> 

如果您使用 HLS.js 设置以下配置,这一点很重要:

var config = 
debug: true,
xhrSetup: function (xhr,url) 
xhr.withCredentials = true; // do send cookie
xhr.setRequestHeader("Access-Control-Allow-Headers","Content-Type, Accept, X-Requested-With");
    xhr.setRequestHeader("Access-Control-Allow-Origin","http://sybdomain.domain.com:8080");
xhr.setRequestHeader("Access-Control-Allow-Credentials","true");

;
var hls = new Hls(config);

其他重要说明:

当您通过网络服务提供 cookie 时,您可以将路径设置为“/”,它将应用于您域中的所有请求。

【讨论】:

嘿,伙计,我也面临同样的问题,最近几天我一直在这个问题上。您能否解释一下步骤 4、5 和 6,因为我是 AWS 的初学者?提前致谢。

以上是关于hls.js CORS 使用 AWS Cloudfront 的 Cookie 问题的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 AWS CloudFormation 在 AWS API Gateway 上应用安全策略?

AWS API Gateway + AWS Lambda 中的 CORS

使用 nginx 和 aws 启用 cors 的正确配置是啥?

AWS 弹性豆茎上的 CORS

使用 BOTO3 为 AWS Api Gateway 自动化 CORS

使用授权方后 AWS Amplify API Gateway cors 错误:aws_iam