如何使用Auth0授权用户访问AWS CloudFront并限制S3资源访问?
问题解答
触发阶段确认
必须在Viewer Request阶段触发Lambda@Edge函数。原因如下:
- 这是CloudFront接收用户请求后的首个处理环节,能在请求转发到S3前完成授权验证,直接拦截未授权请求,避免无效流量消耗S3资源。
- 可在该阶段修改请求路径(比如自动拼接用户sub前缀),确保请求指向用户专属的S3目录。
Lambda@Edge代码实现(Node.js)
以下代码实现核心逻辑:提取并验证Auth0 JWT令牌,校验请求路径与sub字段的匹配关系,验证通过后放行,否则返回403。
依赖准备
需要安装jsonwebtoken和jwks-rsa库,打包时将依赖包含进Lambda部署包(推荐使用Node.js 18.x版本,兼容Lambda@Edge运行环境)。
代码示例
const jwt = require('jsonwebtoken'); const jwksClient = require('jwks-rsa'); // 替换为你的Auth0实际配置 const AUTH0_DOMAIN = 'your-auth0-domain.auth0.com'; const AUTH0_AUDIENCE = 'your-app-audience'; // 对应Auth0应用的Audience参数 const JWKS_URI = `https://${AUTH0_DOMAIN}/.well-known/jwks.json`; // 缓存Auth0公钥,减少重复请求 const client = jwksClient({ jwksUri: JWKS_URI, cache: true, cacheMaxEntries: 5, cacheMaxAge: 600000 // 10分钟缓存有效期 }); function getSigningKey(header, callback) { client.getSigningKey(header.kid, (err, key) => { if (err) return callback(err); const signingKey = key.publicKey || key.rsaPublicKey; callback(null, signingKey); }); } exports.handler = async (event) => { const request = event.Records[0].cf.request; const headers = request.headers; // 检查Authorization头是否存在且格式正确 if (!headers.authorization || !headers.authorization[0].value.startsWith('Bearer ')) { return generateUnauthorizedResponse('缺少或无效的Authorization请求头'); } const token = headers.authorization[0].value.replace('Bearer ', ''); try { // 验证JWT令牌合法性 const decoded = await new Promise((resolve, reject) => { jwt.verify(token, getSigningKey, { audience: AUTH0_AUDIENCE, issuer: `https://${AUTH0_DOMAIN}/`, algorithms: ['RS256'] }, (err, decoded) => { if (err) reject(err); else resolve(decoded); }); }); const userSub = decoded.sub; const requestPath = request.uri; // 模式1:校验请求路径是否以用户sub为前缀(如 /auth0|12345/file.txt) if (!requestPath.startsWith(`/${userSub}/`)) { return generateForbiddenResponse('你无权访问该资源'); } // 模式2:自动为请求路径添加sub前缀(用户请求/file.txt,实际访问S3的/auth0|12345/file.txt) // request.uri = `/${userSub}${requestPath}`; // 验证通过,放行请求 return request; } catch (err) { console.error('JWT验证失败:', err); return generateUnauthorizedResponse('令牌无效或已过期'); } }; // 生成401未授权响应 function generateUnauthorizedResponse(message) { return { status: '401', statusDescription: 'Unauthorized', headers: { 'content-type': [{ key: 'Content-Type', value: 'application/json' }] }, body: JSON.stringify({ error: message }) }; } // 生成403禁止访问响应 function generateForbiddenResponse(message) { return { status: '403', statusDescription: 'Forbidden', headers: { 'content-type': [{ key: 'Content-Type', value: 'application/json' }] }, body: JSON.stringify({ error: message }) }; }
关键注意事项
- Auth0配置:确保JWT的
audience和issuer与你的Auth0应用完全一致,否则验证会失败。 - Lambda部署:Lambda@Edge函数必须部署在
us-east-1区域,再关联到目标CloudFront分配。 - CloudFront缓存策略:需将
Authorization头加入缓存策略的「包含的请求头」列表,确保CloudFront将该头传递给Lambda@Edge。 - S3存储结构:S3桶内文件需按
{sub}/{filename}的结构组织(注意Auth0的sub可能包含|等特殊字符,需确保S3路径支持)。 - 错误处理:代码覆盖了令牌缺失、验证失败、路径不匹配等场景的错误响应,可根据业务需求调整返回内容。
内容的提问来源于stack exchange,提问作者ck0mpana
相关产品推荐
相关产品推荐

