NextJS中使用CloudFront签名Cookie无法播放视频内容的问题
概述
我正在搭建一个基于用户权限展示私有视频的网站:前端采用NextJS(运行在http://localhost:3000),后端采用NestJS(运行在http://localhost:5000),视频存储在私有S3桶中,用户授权后通过CloudFront生成的签名Cookie访问视频内容。
问题
当浏览器已正确存储CloudFront-Key-Pair-Id、CloudFront-Policy、CloudFront-Signature三个Cookie时,直接访问视频地址https://xxxxxx.cloudfront.net/video/intro.mp4可正常播放,但在NextJS应用的播放器中尝试加载时,视频无法播放,返回错误:
'http://localhost:3000' 已被CORS策略阻止:请求的资源上不存在 'Access-Control-Allow-Origin' 标头。
环境配置
S3存储桶
- CORS策略
[ { "AllowedHeaders": [ "*" ], "AllowedMethods": [ "GET" ], "AllowedOrigins": [ "https://xxxxxxx.cloudfront.net" ], "ExposeHeaders": [ "ETag", "Access-Control-Allow-Origin" ] } ]
- 存储桶策略
{ "Version": "2008-10-17", "Id": "PolicyForPrivateContent", "Statement": [ { "Sid": "AllowCloudFrontServicePrincipal", "Effect": "Allow", "Principal": { "Service": "cloudfront.amazonaws.com" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::xxxxx-private/*", "Condition": { "StringEquals": { "AWS:SourceArn": "arn:aws:cloudfront::xxxxxx" } } } ] }
CloudFront
- 源请求策略

NestJS后端
- 主文件CORS配置
app.enableCors({ origin: 'http://localhost:3000', credentials: true, });
- 控制器设置Cookie代码
async access() { const cookies = await this.service.getAccess(id); response.cookie( 'CloudFront-Key-Pair-Id', cookies['CloudFront-Key-Pair-Id'], { domain: 'localhost', httpOnly: true, }, ); response.cookie('CloudFront-Policy', cookies['CloudFront-Policy'], { domain: 'localhost', httpOnly: true, }); response.cookie( 'CloudFront-Signature', cookies['CloudFront-Signature'], { domain: 'localhost', httpOnly: true, }, ); return 'Success'; }
NextJS前端
- API调用代码
const response = await axios.get(`${this.client}/${url}`, { headers: { ...headers, Authorization: `Bearer ${getCookie("Access-Token")}`, }, withCredentials: true, });
解决方案
1. 修正CloudFront的CORS配置
CloudFront作为请求入口,需允许http://localhost:3000的跨域请求:
- 进入CloudFront控制台,找到对应分发,切换到行为标签
- 编辑目标行为,在缓存策略和源请求策略部分,确保关联包含
Origin请求头的源请求策略 - 在行为的**跨域资源共享(CORS)**设置中,添加允许源
http://localhost:3000,并启用CORS选项
2. 更新S3存储桶的CORS策略
将AllowedOrigins添加http://localhost:3000,修改后策略如下:
[ { "AllowedHeaders": [ "*" ], "AllowedMethods": [ "GET" ], "AllowedOrigins": [ "https://xxxxxxx.cloudfront.net", "http://localhost:3000" ], "ExposeHeaders": [ "ETag", "Access-Control-Allow-Origin" ] } ]
3. 修正Cookie的域名配置
当前NestJS设置Cookie的domain为localhost,但这些Cookie需要发送到CloudFront域名才能生效,修改控制器中的Cookie配置:
response.cookie( 'CloudFront-Key-Pair-Id', cookies['CloudFront-Key-Pair-Id'], { domain: '.xxxxxx.cloudfront.net', // 前缀点适配子域名 httpOnly: true, secure: process.env.NODE_ENV === 'production', // 生产环境开启,localhost测试可关闭 sameSite: 'none', // 跨域请求需设置为none }, ); // CloudFront-Policy、CloudFront-Signature两个Cookie做同样修改
4. 确保播放器请求携带Cookie
在NextJS播放器组件中,确保请求CloudFront视频地址时携带凭证。比如使用原生<video>标签时添加属性:
<video src="https://xxxxxx.cloudfront.net/video/intro.mp4" crossOrigin="use-credentials" controls />
若使用第三方播放器库,需配置对应跨域携带凭证选项。
内容的提问来源于stack exchange,提问作者user16257618

