如何使用来自AWS S3的预签名Cookie在ReactPlayer上实现电影播放器

问题描述

我正在开发一个网站,以使用React和AWS S3提供视频点播服务。
我必须先授权才能观看视频。
因此,我考虑在请求时使用签名的Cookie。

使用curl的请求成功。

curl -H 'Cookie:CloudFront-Policy=eyJTd*******************;CloudFront-Signature=b8wt************************************; CloudFront-Key-Pair-Id=AP**********' http://*********.cloudfront.net/hogehoge.m3u8

但是我无法在React上获取文件
我的代码在那里。

export function Movie(){
    document.cookie = `CloudFront-Key-Pair-Id=${"AP**************"}; `
    document.cookie = `CloudFront-Policy=${"eyJT*****************"}; `
    document.cookie = `CloudFront-Signature=${"b8wt****************"}; `

    <ReactPlayer
        url={"http://******.cloudfront.net/hogehoge.m3u8"}
        controls
        config={{
            file: {
                hlsOptions: { 
                xhrSetup: function(xhr: any,url: any) {
                    xhr.withCredentials = true // send cookies
                }
                }
            }
        }}
    >
}

Chrome(Image)上的错误消息

Request URL: http://*****.cloudfront.net/hogehoge.m3u8
Referrer Policy: strict-origin-when-cross-origin
Connection: keep-alive
Content-Length: 146
Content-Type: text/xml
Date: Tue,27 Oct 2020 05:54:03 GMT
Server: CloudFront
Via: 1.1 *********.cloudfront.net (CloudFront)
X-Amz-Cf-Id: *******
X-Amz-Cf-Pop: NRT12-C3
X-Cache: Error from cloudfront
Accept: */*
Accept-Encoding: gzip,deflate
Accept-Language: ja-JP,ja;q=0.9,en-JP;q=0.8,en;q=0.7,en-US;q=0.6
Connection: keep-alive
DNT: 1
Host: ********.cloudfront.net
Origin: http://localhost:3000
Referer: http://localhost:3000/
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/86.0.4240.111 Safari/537.36

该请求似乎不包含cookie。
我该如何解决该问题?

解决方法

显然,问题之一是 CORS 政策的执行。如果您查看响应,您可以看到主机/引用者(即 localhost:3000)与目标不同(OP 已编辑,但我们假设它是 blah.cloudfront.net)。 即使在解决 CORS 问题之后,您也需要确保正确设置 Cloudfront 和 S3。 我正在列出对我有用的内容:

  1. 将自定义域分配给 cloudfront,使自定义域成为您的应用前端将运行的子域。在 OP 的情况下,他使用的是 localhost:3000;很可能他正在测试他的开发设置,但他必须在某个域中部署这个应用程序:我们称之为“myapp.com”。所以,他可以分配一个自定义域,比如 cdn.myapp.com 指向 blah.cloudfront.net。您需要为新的自定义域创建/导入自定义 SSL 证书;默认的 cloudfront 证书将不起作用。enter image description here 请参阅:https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/CNAMEs.html[![enter 此处的图像描述]2]2 第一个没有自定义域,因此是空的 CNAME柱子。第二个是有一个自定义域,因此我们在那里打印了那个。您可以通过这种方式验证您的自定义域是否指向了 Cloudfront 分发版。
  2. Cloudfront 行为:我假设您已经设置了受信任的密钥组,因为此时您已经有了签名的 cookie。但是,您需要创建自定义缓存策略和源请求策略。 enter image description here 查看自定义缓存策略的以下屏幕截图:enter image description here 和源请求策略:enter image description here 需要注意的是,您需要将这些标头列入白名单:Origin、Access-Control-请求方法、访问控制允许来源、访问控制请求标头。 (您可能会注意到 Access-Control-Allow-Origin 不在下拉列表中;直接输入即可!)。此外,允许所有 cookie。
  3. S3 CORS 配置:转到 S3 存储桶并单击权限选项卡。向下滚动到 CORS 配置。免责声明:我只是粘贴了对我有用的内容。这背后的基本原理是,在我的场景中,这个 S3 将被 CDN 或应用程序访问。我尝试将 '*' 放宽,但 Chrome 上的 CORS 策略抱怨我无法在 AllowedOrigins 中使用通配符条目!
[
    {
        "AllowedHeaders": [
            "*"
        ],"AllowedMethods": [
            "PUT","POST","GET","HEAD","DELETE"
        ],"AllowedOrigins": [
            "cdn.myapp.com","myapp.com","https://cdn.myapp.com","https://myapp.com"
        ],"ExposeHeaders": [
            "ETag"
        ]
    }
]
  1. react-player:我正在使用这样的 react-player(注意正在设置 forceHLS 选项,但它再次特定于我的用例。我认为这通常不是强制性的)
<ReactPlayer
    className="react-player"
    url={url}
    controls={controls}
    light={light}
    config={
      {
        file: {
          forceHLS: true,hlsOptions: {
            xhrSetup: function (xhr,url) {
              xhr.withCredentials = true; // send cookies
            },},}
    }
    playIcon={<PlayIcon />}
    width="100%"
    height="100%"
  />