【发布时间】:2020-10-18 13:25:30
【问题描述】:
我正在尝试转发客户端对流的请求,它使最初从视频播放器发出的请求保持不变:
Content-Type: Keep-Alive;
Range: 0-
...
我在用什么:
- 前端:Web - ReactJS
- 后端:PHP REST API
- CDN:AWS CloudFront
- 存储:AWS S3
建筑图形
原因:
我需要能够通过 REST 使用我们自己的 JWT 中间件对用户进行身份验证,以验证他们是否可以访问该文件。
约束:
不能使用nginx 转发请求,除非还有办法通过 PHP 中间件对其进行身份验证。
我的调查结果:
aws php sdk
我查看了 AWS PHP,但似乎缺少有关此特定功能的文档。
guzzle + php curl
恐怕我缺乏关于我需要传递到 CloudFront 以使其工作的知识。
cloudfront signed url/signature
除非我弄错了,否则这不会有帮助,因为访问的视频过期时间将由 AWS 设置,而不是由应用程序的 REST API 设置,因此如果他们刷新 JWT,它将不会使用签名进行更新。
why not s3 directly?
S3 不支持像 Range: 0-100 bytes 这样的块的标头。
任何帮助或建议都将不胜感激,即使这意味着建议购买一些预先构建的东西来看看他们是如何实施的。
======= 更新:2020 年 6 月 29 日 =======
在@ChrisWilliams 的推荐下,我最终在 AWS Lambda@Edge 上创建了一个脚本,配置如下:
触发器: CloudFront - viewer request
viewer request 的原因是因为它是从用户原始请求中获取 GET 查询参数的唯一方法。
功能代码:
(请原谅非常粗糙的代码以使事情正常运行)
文件: index.js
// IMPORTS
const zlib = require('zlib');
const https = require('https');
// HTML ERROR TEMPLATE
const content = `
<\!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Unauthorized Page</title>
</head>
<body>
<p>Unauthorized!</p>
</body>
</html>
`;
// TRIGGER FUNCTION
exports.handler = async (event, context, callback) => {
// Getting request and response
const originalResponse = event.Records[0].cf.response;
const request = event.Records[0].cf.request;
// Setup for html page (cont content)
const buffer = zlib.gzipSync(content);
const base64EncodedBody = buffer.toString('base64');
// Response Templates
var response401 = {
headers: {
'content-type': [{key:'Content-Type', value: 'text/html; charset=utf-8'}],
'content-encoding' : [{key:'Content-Encoding', value: 'gzip'}]
},
body: base64EncodedBody,
bodyEncoding: 'base64',
status: '401',
statusDescription: "OK"
};
var response500 = {
headers: {
'content-type': [{key:'Content-Type', value: 'text/html; charset=utf-8'}],
'content-encoding' : [{key:'Content-Encoding', value: 'gzip'}]
},
body: base64EncodedBody,
bodyEncoding: 'base64',
status: '500',
statusDescription: "OK"
};
// Perform Http Request
const response = await new Promise((resolve, reject) => {
// Expected ?token=ey...
const req = https.get(`https://myauthserver.com/?${(request && request.querystring) || ''}`, function(res) {
if (res.statusCode !== 200) {
return reject(response401);
}
return resolve({
status: '200'
});
});
req.on('error', (e) => {
reject(response500);
});
}).catch(error => error);
// Get results from promise
const results = await response;
if (results.status === '200') {
// Successful request - continue with the rest of the process
callback(null, request);
}
// Not successful, show the errors results (401 or 500)
callback(null, results);
};
注意:您必须尝试几次,以防因缓存而出现任何拼写错误或语法错误。我还建议尝试使用不同的 IP 地址来验证对内容的访问。更不用说,如果返回的请求的格式不正确,base64EncodedBody 会出现502 的情况。
双重注意:这是在查看了来自 AWS 的无效或过时的教程,并查看了多个开发人员的 cmets 无法正常工作之后。
【问题讨论】:
-
为什么不能使用 Labda@Edge 函数来验证 JWT 令牌?
-
这将如何工作?身份验证中间件位于单独的服务器上,因此 CloudFront 是否有一个特殊的钩子/中间件检查外部身份验证,如果是,它是否专门与 Lambda 绑定?
-
您可以拥有一个处理 JWT 标头的 Lambda@Edge 函数,可以在函数本身内进行验证,也可以调用您必须验证的外部端点。如果它无效,它将拒绝阻止它被转发的请求。这是亚马逊发表的一篇文章:aws.amazon.com/blogs/networking-and-content-delivery/…
-
@apokryfos 我提到我尝试过,aws php ask、guzzle、cloudfront 和 aws php sdk for s3。 PHP 代理看起来很有希望,我会检查一下。谢谢你。
标签: php laravel amazon-web-services curl amazon-cloudfront