如何为Cognito授权的LambdaRestApi(CDK)配置CORS跨域
问题原因
当你为LambdaRestApi设置defaultCorsPreflightOptions时,CDK会自动为所有API资源生成OPTIONS预检请求方法,而这个方法会默认继承defaultMethodOptions中的Cognito授权配置。但浏览器发送的预检请求不会携带身份凭证,将Cognito授权(包含authorizationScopes)应用到OPTIONS方法会触发API Gateway的校验错误——因为授权范围仅对携带有效用户池token的请求有意义,预检请求不满足这个条件。
解决方案
你需要让OPTIONS方法跳过授权校验,以下是三种可行的实现方式:
方式一:让Lambda处理CORS响应
直接在Lambda函数中返回CORS响应头,同时单独处理OPTIONS请求,无需依赖API Gateway自动生成预检方法:
Lambda代码示例(Node.js):
exports.handler = async (event) => { // 统一返回CORS头 const corsHeaders = { "Access-Control-Allow-Origin": "*", // 可替换为指定域名 "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS", "Access-Control-Allow-Headers": "Content-Type, Authorization" }; // 处理预检请求,直接返回200 if (event.httpMethod === 'OPTIONS') { return { statusCode: 200, headers: corsHeaders, body: '' }; } // 业务逻辑处理 const response = { statusCode: 200, headers: corsHeaders, body: JSON.stringify('处理结果') }; return response; };
CDK代码中移除defaultCorsPreflightOptions配置即可,所有请求(包括预检)都会代理到Lambda处理。
方式二:手动添加OPTIONS方法并禁用授权
手动为API资源创建OPTIONS方法,使用Mock集成直接返回CORS头,并明确设置授权类型为NONE:
CDK代码示例:
import { MockIntegration, PassthroughBehavior, AuthorizationType } from 'aws-cdk-lib/aws-apigateway'; const restApi = new LambdaRestApi(this, 'MyServiceRestApi', { handler: serviceAPIGWLambdaHandler, domainName: { domainName: `service.${rootDomain}`, certificate: Certificate.fromCertificateArn( this, `explanation`, serviceDomainCertificate.certificateArn, ), }, proxy: true, endpointTypes: [EndpointType.EDGE], defaultMethodOptions: { authorizationType: AuthorizationType.COGNITO, authorizer, authorizationScopes: this.oauthScopes, methodResponses: [ { statusCode: '200', }, ], }, }); // 定义添加CORS预检方法的工具函数 const addCorsOptions = (resource: IResource) => { resource.addMethod('OPTIONS', new MockIntegration({ integrationResponses: [{ statusCode: '200', responseParameters: { 'method.response.header.Access-Control-Allow-Origin': "'*'", 'method.response.header.Access-Control-Allow-Methods': "'GET,POST,PUT,DELETE,OPTIONS'", 'method.response.header.Access-Control-Allow-Headers': "'Content-Type,Authorization'", }, }], passthroughBehavior: PassthroughBehavior.NEVER, requestTemplates: { 'application/json': '{"statusCode": 200}', }, }), { methodResponses: [{ statusCode: '200', responseParameters: { 'method.response.header.Access-Control-Allow-Origin': true, 'method.response.header.Access-Control-Allow-Methods': true, 'method.response.header.Access-Control-Allow-Headers': true, }, }], // 关键:OPTIONS方法无需授权 authorizationType: AuthorizationType.NONE, }); }; // 为根资源和代理资源添加OPTIONS方法 const rootResource = restApi.root; const proxyResource = rootResource.getResource('{proxy+}')!; addCorsOptions(rootResource); addCorsOptions(proxyResource);
方式三:修改自动生成的OPTIONS方法配置
保留defaultCorsPreflightOptions,通过CDK的属性覆盖功能,修改自动生成的OPTIONS方法的授权配置:
CDK代码示例:
const restApi = new LambdaRestApi(this, 'MyServiceRestApi', { handler: serviceAPIGWLambdaHandler, domainName: { domainName: `service.${rootDomain}`, certificate: Certificate.fromCertificateArn( this, `explanation`, serviceDomainCertificate.certificateArn, ), }, defaultCorsPreflightOptions: { allowOrigins: Cors.ALL_ORIGINS }, proxy: true, endpointTypes: [EndpointType.EDGE], defaultMethodOptions: { authorizationType: AuthorizationType.COGNITO, authorizer, authorizationScopes: this.oauthScopes, methodResponses: [ { statusCode: '200', }, ], }, }); // 遍历所有资源,修改OPTIONS方法的授权配置 const updateOptionsMethods = (resource: IResource) => { const optionsMethod = resource.methods.find(m => m.httpMethod === 'OPTIONS'); if (optionsMethod) { // 设置授权类型为NONE (optionsMethod as Method).addPropertyOverride('AuthorizationType', AuthorizationType.NONE); // 移除自动添加的授权器和范围配置 optionsMethod.addPropertyDeletionOverride('AuthorizerId'); optionsMethod.addPropertyDeletionOverride('AuthorizationScopes'); } // 递归处理子资源 resource.children.forEach(child => updateOptionsMethods(child as IResource)); }; updateOptionsMethods(restApi.root);
内容的提问来源于stack exchange,提问作者Pouyan
相关产品推荐
相关产品推荐

