【问题标题】:How to configure CORS for AWS API Gateway using OpenAPI?如何使用 OpenAPI 为 AWS API Gateway 配置 CORS?
【发布时间】:2020-10-25 01:54:51
【问题描述】:

我有一个通过 CDK 部署的 API 的 OpenAPI 规范。规范看起来像:

openapi: 3.0.1
info:
  title: My API
  description: My REST API with CORS enabled
  version: 0.1.0

x-amazon-apigateway-cors:
  allowOrigins:
    - "*"
  allowCredentials: true
  exposeHeaders:
    - "x-apigateway-header"
    - "x-amz-date"
    - "content-type"
  maxAge: 3600
  allowMethods:
    - "*"
  allowHeaders":
    - "x-apigateway-header"
    - "x-amz-date"
    - "content-type"
    - "Authorization"

components:
  securitySchemes:
    lambda:
      type: "apiKey"
      name: "Authorization"
      in: "header"
      x-amazon-apigateway-authtype: "custom"
      x-amazon-apigateway-authorizer:
        authorizerUri: "{{my-lambda-authorizer}}"
        authorizerResultTtlInSeconds: 300
        type: "token" 

paths:
  /user/{id}:
    get:
      summary: Get info of specified user.
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
      security:
        - lambda: []
      x-amazon-apigateway-integration:
        uri: "{{my-lambda}}"
        passthroughBehavior: "when_no_match"
        httpMethod: "POST"
        type: "aws_proxy"

当我尝试通过fetch() 访问它时,我收到错误Failed to load resource: Origin http://localhost:8000 is not allowed by Access-Control-Allow-Origin。

fetch('https://api.example.com/user/1')
        .then(response => response.json())
        .then((user: User) => {
            // do something
        })
        .catch((err) => {
            console.log("Error: " + err);
        });

API 可通过api.example.com 访问,我正在使用 Gatsby 在本地运行网站localhost:8000。

AWS docs 似乎表明当我将 x-amazon-apigateway-cors 放在规范的根目录时启用了 CORS,但是当我尝试访问 API 时似乎没有启用(或工作)CORS。如何在无需在控制台中配置的情况下为我的 API 启用 CORS?

【问题讨论】:

    标签: amazon-web-services aws-lambda amazon-cloudformation aws-api-gateway aws-cdk


    【解决方案1】:

    Amazon API Gateway 提供两种类型的 API:REST API 和 HTTP API。 REST API 是最初随 Amazon API Gateway 引入的那种 API,而 HTTP APIs got announced at the end of 2019。

    根据您的 OpenAPI 规范的描述,我假设您正在尝试部署 REST API。 x-amazon-apigateway-cors OpenAPI 扩展仅适用于 HTTP API。

    您现在有两个选择:要么切换到使用 HTTP API,要么手动配置 CORS。只要您不需要features only supported by REST APIs,我建议您改用 HTTP API,因为这是 Amazon API Gateway 提供的更现代的 API。

    如果您想使用 REST API,启用 CORS 需要更多手动配置。 AWS 在Enabling CORS for a REST API resource 中记录了这一点。本质上,您必须确保您的集成返回正确的 CORS 标头。对于 NodeJS AWS Lambda 函数,可能如下所示:

    exports.handler = async (event) => {
        const response = {
            statusCode: 200,
            headers: {
                "Access-Control-Allow-Headers" : "Content-Type",
                "Access-Control-Allow-Origin": "https://www.example.com",
                "Access-Control-Allow-Methods": "OPTIONS,POST,GET"
            },
            body: JSON.stringify('Hello from Lambda!'),
        };
        return response;
    };
    

    要使 CORS 飞行前请求正常工作,您还必须确保 OPTIONS 请求也返回正确的标头。实现这一目标的最简单方法是将 OPTIONS 请求的模拟集成添加到您的 OpenAPI 规范中。看起来像:

    options:
      responses:
        '200':
          description: Default response
          headers:
            Access-Control-Allow-Headers:
              schema:
                type: string
            Access-Control-Allow-Methods:
              schema:
                type: string
            Access-Control-Allow-Origin:
              schema:
                type: string
      x-amazon-apigateway-integration:
        type: mock
        requestTemplates:
          application/json: |
            {"statusCode" : 200}
        responses:
          default:
            statusCode: 200
            responseParameters:
              method.response.header.Access-Control-Allow-Headers: "'*'"
              method.response.header.Access-Control-Allow-Methods: "'OPTIONS,POST'"
              method.response.header.Access-Control-Allow-Origin: "'https://example.com/'"
    

    还请注意modern browsers don't support localhost as origin for CORS,因此您可能还需要解决这个问题。

    【讨论】:

    • 谢谢,这是一个非常有帮助的答案。你是对的,它是一个 REST API,因为 (a) 它是唯一通过 CDK 支持 OpenAPI 的 API,并且 (b) 我需要通过检查令牌来进行授权,因为它看起来不像 Cognito 授权方足够丰富我想要。根据您的回答,我已经设法通过从代理本身返回标头来使 CORS 工作,但前提是我禁用了自定义 lambda 授权程序。为了能够在这里使用 lambda 授权器,我还需要做些什么吗?
    • 您的客户端请求是否成功通过了授权人?因为如果不是,授权方将生成响应,其中不包含必要的 CORS 标头。
    • 有没有办法让授权方返回标头?文档建议抛出一个异常来指示 401,所以我猜这会导致标题不被传递。
    • 原来在 StackOverflow 上有另一个问题:stackoverflow.com/questions/36913196/… :-)
    • 非常感谢
    猜你喜欢
    • 2018-07-13
    • 2020-10-25
    • 2018-03-08
    • 2021-03-08
    • 1970-01-01
    • 2019-07-09
    • 2016-10-29
    • 2020-08-17
    • 2020-03-14
    相关资源
    最近更新 更多