You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 11:58:13