如何使用 AWS SAM 启用 CORS

问题描述 投票:0回答:6

我正在尝试在我的 AWS SAM 应用程序中启用 CORS。这是我的

template.yaml
的片段:

Globals:
  Api:
    Cors:
      AllowMethods: "'*'"
      AllowHeaders: "'*'"
      AllowOrigin: "'*'"

Resources:
  MyApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: prod
      Auth:
        Authorizers:
          MyCognitoAuthorizer: ...

  getByIdFunc:
    Type: AWS::Serverless::Function
    Properties:
      Handler: src/handler.handle
      Events:
        ApiEvent:
          Type: Api
          Properties:
            Path: /{id}
            Method: GET
            RestApiId: !Ref MyApi

根据此Using CORS with AWS SAMhttps://github.com/aws/serverless-application-model/issues/373,cors配置应该可以工作,但遗憾的是API响应上没有设置标头,如下所示。

< HTTP/2 200 
< content-type: application/json
< content-length: 770
< date: Tue, 13 Apr 2021 19:55:31 GMT
< x-amzn-requestid: ...
< x-amz-apigw-id: ...
< x-amzn-trace-id: Root=1-...-...;Sampled=0
< x-cache: Miss from cloudfront
< via: 1.1 ...cloudfront.net (CloudFront)
< x-amz-cf-pop: FRA2-C2
< x-amz-cf-id: ...==
< 
* Connection #0 to host ....execute-api.eu-central-1.amazonaws.com left intact
[{"model": ..}]

我还尝试将 cors 配置添加到 API 定义 (MyApi) 本身,如官方文档中所述,但没有成功。

我可以自己在响应中添加标头,但我宁愿将其放在模板文件中。

amazon-web-services cors aws-api-gateway aws-sam infrastructure-as-code
6个回答
21
投票

为我解决这个问题的方法是将以下内容添加到我的 template.yaml 中:

Globals:
    Api:
        Cors:
            AllowMethods: "'GET,POST,OPTIONS'"
            AllowHeaders: "'content-type'"
            AllowOrigin: "'*'"
            # AllowCredentials: true  Uncomment only if you choose a specific origin instead of the * wildcard.

就像 nirvana124 和 Nitesh 所说,您还需要在每个端点中返回这些标头和响应:

return {
    statusCode: 200,
    headers: {
        "Access-Control-Allow-Headers" : "Content-Type",
        "Access-Control-Allow-Origin": "*", // Allow from anywhere 
        "Access-Control-Allow-Methods": "GET" // Allow only GET request 
    },
    body: JSON.stringify(response)
}

9
投票

使用 SAM/CloudFormation 或 AWS 控制台,您可以为 OPTIONS 方法设置 CORS 标头,该方法将在调用实际 API 方法(GET/POST 等)之前由浏览器调用。邮递员或任何其他服务只会调用您的端点。

当我们将 lambda 代理与 API Gateway 一起使用时,我们需要在 lambda 的响应对象中设置 CORS 标头。

要为 Lambda 代理集成启用 CORS,您必须将 Access-Control-Allow-Origin:

domain-name
添加到输出标头。域名可以是任何域名的
*

return {
        statusCode: 200,
        headers: {
            "Access-Control-Allow-Headers" : "Content-Type",
            "Access-Control-Allow-Origin": "*", // Allow from anywhere 
            "Access-Control-Allow-Methods": "GET" // Allow only GET request 
        },
        body: JSON.stringify(response)
    }

5
投票

对于使用 API Gateway 版本 2 (HttpApi) 的任何人来说,它不支持“AddDefaultAuthorizerToCorsPreflight”,至少在其文档中没有指定。

相反(根据 AWS guidelines),我们需要在 OPTIONS /{proxy+} 的 lambda 函数中添加一条路由,并关闭该路由的身份验证。

MyHttpApi:
 Type: AWS::Serverless::HttpApi
 Properties:
  Auth:
    DefaultAuthorizer: OAuth2
    Authorizers:
      OAuth2:
        JwtConfiguration:
          issuer: "..."
          audience:
            - ...
        IdentitySource: "$request.header.Authorization"
  CorsConfiguration:
    AllowOrigins:
      - "*"
    AllowMethods: 
      - GET
      - POST
      - OPTIONS
    AllowHeaders:
      - Content-Type
      - Accept
      - Access-Control-Allow-Headers
      - Access-Control-Request-Method
      - Access-Control-Request-Headers
      - Authorization
MyLambdaFunction:
 Type: AWS::Serverless::Function
 Properties:
  Handler: index.handler
  Events:
    CorsPreflightEvent:
      Type: HttpApi
      Properties:
        Path: /{proxy+}
        Method: OPTIONS
        Auth:
          Authorizer: NONE
        ApiId: !Ref MyHttpApi

3
投票

使用您的脚本,在 API Gateway 上启用了 CORS,但 SAM 始终创建从 API Gateway 到 Lambda 的 PROXY 集成,这意味着 API Gateway 无法添加任何集成响应,它将传递从 LAMBDA 收到的响应。这就是为什么您需要在 lambda 内部处理 CORS 标头,而不是依赖 API 网关。下面是从 LAMBDA 返回的示例代码以及响应。

return {
        statusCode: 200,
        headers: {
            "Access-Control-Allow-Headers" : "Content-Type,X-Amz-Date,Authorization,X-Api-Key,x-requested-with",
            "Access-Control-Allow-Origin": "*", // Allow from anywhere 
            "Access-Control-Allow-Methods": "OPTIONS,POST,GET,PUT,DELETE,PATCH" // Allow only GET request 
        },
        body: JSON.stringify(response)
    }

3
投票

迟到了,但对于 Google 的其他人来说:将其添加到 Auth 部分,这将不允许授权者处理 CORS HTTP 标头

Api:
  Auth:
    AddDefaultAuthorizerToCorsPreflight: false

0
投票

要在 API 网关和 CloudFormation/SAM 上启用 Cors,我们需要做一些事情:

  1. 将 OPTIONS 方法添加到您的端点以提供预检握手响应(官方文档)。
  2. 在响应部分定义所需的标头占位符( Access-Control-Allow-Origin 等)
  3. 为集成部分中的这些标头赋值(“*”等)
  4. 更新您的响应模板以将响应中的这些标头传递给客户端

这是一个示例文件,显示了如何定义它:

AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'

Resources:
  SignupApi:
    Type: 'AWS::Serverless::Api'
    Properties:
      StageName: prod
      Cors:
        AllowMethods: "'POST'"
        AllowHeaders: "'Content-Type'"
        AllowOrigin: "'*'"
      DefinitionBody:
        swagger: '2.0'
        info:
          title: 'Signup API'
          version: '1.0.0'
        paths:
          /signup:
            options:
              summary: CORS support
              description: |
                Enable CORS by returning correct headers
              consumes:
                - application/json
              produces:
                - application/json
              tags:
                - CORS
              x-amazon-apigateway-integration:
                type: mock
                requestTemplates:
                  application/json: |
                    {
                      "statusCode" : 200
                    }
                responses:
                  "default":
                    statusCode: "200"
                    responseParameters:
                      method.response.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key'"
                      method.response.header.Access-Control-Allow-Methods: "'*'"
                      method.response.header.Access-Control-Allow-Origin: "'*'"
                    responseTemplates:
                      application/json: |
                        {}
              responses:
                '200':
                  description: Default response for CORS method
                  headers:
                    Access-Control-Allow-Headers:
                      type: "string"
                    Access-Control-Allow-Methods:
                      type: "string"
                    Access-Control-Allow-Origin:
                      type: "string"
            post:
              produces:
                - application/json
              responses:
                '200':
                  description: Default response for CORS method
                  headers:
                    Access-Control-Allow-Headers:
                      type: "string"
                    Access-Control-Allow-Methods:
                      type: "string"
                    Access-Control-Allow-Origin:
                      type: "string"
              parameters:
                - name: body
                  in: body
                  required: true
                  schema:
                    $ref: '#/definitions/SignupRequest'
              x-amazon-apigateway-integration:
                uri: !Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${SignupFunction.Arn}/invocations'
                passthroughBehavior: 'when_no_match'
                httpMethod: 'POST'
                type: 'aws'
                integrationHttpMethod: 'POST'
                requestTemplates:
                  application/json:  |
                    #set($allHeaders = $input.params().header)
                        {
                          #foreach($header in $allHeaders.keySet())
                            "$header": "$util.escapeJavaScript($allHeaders.get($header))" #if($foreach.hasNext),#end
                          #end
                          "body": $input.json("$.body")
                        }
                responses:
                  default:
                    statusCode: '200'
                    responseParameters:
                      method.response.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key'"
                      method.response.header.Access-Control-Allow-Methods: "'*'"
                      method.response.header.Access-Control-Allow-Origin: "'*'"
                    responseTemplates:
                      application/json: '$input.json("$.body")'
        definitions:
          SignupRequest:
            type: 'object'
            properties:
              name:
                type: 'string'
              email:
                type: 'string'
              password:
                type: 'string'
  SignupFunction:
    Type: 'AWS::Serverless::Function'
    Properties:
      Handler: index.lambda_handler
      Runtime: python3.8
      InlineCode: |
        import json

        def lambda_handler(event, context):
            response = {
                'statusCode': 200,
                'body': json.dumps({'message': 'Signup successful'})
            }
            return response
      Events:
        SignUp:
          Type: Api
          Properties:
            Path: /signup
            Method: post
            RestApiId: !Ref SignupApi
© www.soinside.com 2019 - 2024. All rights reserved.