CloudFront 与 Lambda@Edge 导致 CORS 问题

CloudFront with Lambda@Edge results in CORS problem

我已将 S3 配置为只能通过 CloudFront 进行访问,并使用根据查看者请求执行的 lambda 进行保护。问题是由于预检调用失败,我无法从 SPA 访问文件。

当我删除 lambda 函数时,一切都开始工作了。这让我感到惊讶,因为 lambda 根本没有修改请求。

这是我的配置:

S3:

CloudFront:

Lambda@Edge(应查看者请求执行)

exports.handler = async (event, context, callback) => {
    let request;
    let token;

    try {
        request = event.Records[0].cf.request;
        const headers = request.headers;
        const authorization = headers['authorization'][0];
        const authorizationValue = authorization.value;
        token = authorizationValue.substring(7);
    } catch (error) {
        console.error("Missing authorization header", error);
        callback(null, missingAuthorizationHeaderResponse);
    }

    if (token) {
        try {
            if (!secret) {
                secret = await getSecret();
            }
            jwt.verify(token, secret);
            console.log("Token valid");
            callback(null, request);
        } catch (error) {
            console.error("Token not valid", error);
            callback(null, invalidTokenResponse);
        }
    } else {
        console.error("Token not found");
        callback(null, missingAuthorizationHeaderResponse);
    }
};

非常感谢您的帮助,因为我在这个案例上花了很多时间,谢谢!

问题是预检调用是在没有任何额外 header 的情况下执行的,在我的例子中,“授权”header 丢失并生成 403。我通过查看日志发现拉姆达。我已经添加了对 lambda 的选项调用的处理。此外,我还必须更改 s3 配置以使响应具有可见的 CORS headers.

Lambda 代码:

 const preflightCall = {
        status: "204",
        headers: {
                'access-control-allow-origin': [{
                    key: 'Access-Control-Allow-Origin',
                    value: "*",
                }],
                 'access-control-request-method': [{
                    key: 'Access-Control-Request-Method',
                    value: "PUT, GET, OPTIONS, DELETE",
                }],
                 'access-control-allow-headers': [{
                    key: 'Access-Control-Allow-Headers',
                    value: "*",
                }]
        },
    };

exports.handler = async (event, context, callback) => {
    let request;
    let token;

    try {
        request = event.Records[0].cf.request;
        if(request.method === 'OPTIONS') {
            console.log('preflight call');
            callback(null, preflightCall);
            return;
        }
        const headers = request.headers;
        const authorization = headers['authorization'][0];
        const authorizationValue = authorization.value;
        token = authorizationValue.substring(7);
    } catch (error) {
        console.error("Missing authorization header", error);
        callback(null, missingAuthorizationHeaderResponse);
    }

    if (token) {
        try {
            if (!secret) {
                secret = await getSecret();
            }
            jwt.verify(token, secret);
            console.log("Token valid");
            callback(null, request);
        } catch (error) {
            console.error("Token not valid", error);
            callback(null, invalidTokenResponse);
        }
    } else {
        console.error("Token not found");
        callback(null, missingAuthorizationHeaderResponse);
    }
};

S3:

[
    {
        "AllowedHeaders": [
            "Authorization"
        ],
        "AllowedMethods": [
            "GET",
            "HEAD",
            "DELETE",
            "POST",
            "PUT"
        ],
        "AllowedOrigins": [
            "*"
        ],
        "ExposeHeaders": [
            "Access-Control-Allow-Origin"
        ],
        "MaxAgeSeconds": 3000
    }
]