具有自定义授权者和 CORS 间歇性 200 然后 403 然后 200 的 AWS API 网关 ...奇怪

Posted

技术标签:

【中文标题】具有自定义授权者和 CORS 间歇性 200 然后 403 然后 200 的 AWS API 网关 ...奇怪【英文标题】:AWS API Gateway with Custom Authorizer and CORS Intermittent 200 then 403 then 200 ... Strange 【发布时间】:2019-01-04 02:05:57 【问题描述】:

我有一个带有自定义授权方的 1 Amazon Api Gateway 设置(授权方基本上只返回允许任何内容)

我启用了 CORS,这是从 jQuery 网页运行的。

我有两种方法

    /vehicles(返回汽车列表) /bookings(返回预订详情)

我看到的行为是第一个请求正常,我看到它拉 OPTIONS,然后执行 GET 请求。 然后,我点击了 OPTIONS 工作的另一种方法,然后 get 返回 403,但如果我再次启动请求(在同一资源上),我得到一个 200

我正在使用 Cloudformation,但在使用无服务器框架时发现了同样的行为。

以下是一些屏幕截图,以证明我的理智,希望其他人已经看到了这种奇怪之处。

以下是我的 Cloudformation YAML 模板的一部分,我边做边学。

 HelloAPI:
    Type: AWS::Serverless::Api
    Properties:
      StageName: !Sub $Environment
      DefinitionBody:
        swagger: 2.0
        info:
          title:
            Ref: AWS::StackName
        securityDefinitions:
          test-authorizer:
            type: apiKey
            name: Authorization
            in: header
            x-amazon-apigateway-authtype: custom
            x-amazon-apigateway-authorizer:
              type: token
              authorizerUri:
                Fn::Sub: arn:aws:apigateway:$AWS::Region:lambda:path/2015-03-31/functions/$AuthorizerFunc.Arn/invocations
              authorizerResultTtlInSeconds: 5
        paths:
          /vehicles:
            get:
              x-amazon-apigateway-integration:
                httpMethod: POST
                type: aws_proxy
                uri:
                  !Sub arn:aws:apigateway:$AWS::Region:lambda:path/2015-03-31/functions/$VehiclesLambda.Arn/invocations
              responses: 
              security:
                - test-authorizer: []
            options:
              tags:
              - "CORS"
              summary: "CORS support"
              description: "Enable CORS by returning correct headers\n"
              consumes:
              - "application/json"
              produces:
              - "application/json"
              parameters: []
              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"
              x-amazon-apigateway-integration:
                type: "mock"
                requestTemplates:
                  application/json: "\n  \"statusCode\" : 200\n\n"
                responses:
                  default:
                    statusCode: "200"
                    responseParameters:
                      method.response.header.Access-Control-Allow-Headers: "'X-Amz-Date,Authorization,X-Api-Key'"
                      method.response.header.Access-Control-Allow-Methods: "'*'"
                      method.response.header.Access-Control-Allow-Origin: "'*'"
                    responseTemplates:
                      application/json: "\n"
          /bookings:
            get:
              x-amazon-apigateway-integration:
                httpMethod: POST
                type: aws_proxy
                uri:
                  !Sub arn:aws:apigateway:$AWS::Region:lambda:path/2015-03-31/functions/$BookingsLambda.Arn/invocations
              responses: 
              security:
                - test-authorizer: []
            options:
              tags:
              - "CORS"
              summary: "CORS support"
              description: "Enable CORS by returning correct headers\n"
              consumes:
              - "application/json"
              produces:
              - "application/json"
              parameters: []
              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"
              x-amazon-apigateway-integration:
                type: "mock"
                requestTemplates:
                  application/json: "\n  \"statusCode\" : 200\n\n"
                responses:
                  default:
                    statusCode: "200"
                    responseParameters:
                      method.response.header.Access-Control-Allow-Headers: "'X-Amz-Date,Authorization,X-Api-Key'"
                      method.response.header.Access-Control-Allow-Methods: "'*'"
                      method.response.header.Access-Control-Allow-Origin: "'*'"
                    responseTemplates:
                      application/json: "\n"

这是我的Anything Goes Authorizer

'use strict';

const generatePolicy = function(principalId, effect, resource) 
    const authResponse = ;
    authResponse.principalId = principalId;
    if (effect && resource) 
        const policyDocument = ;
        policyDocument.Version = '2012-10-17';
        policyDocument.Statement = [];
        const statementOne = ;
        statementOne.Action = 'execute-api:Invoke';
        statementOne.Effect = effect;
        statementOne.Resource = resource;
        policyDocument.Statement[0] = statementOne;
        authResponse.policyDocument = policyDocument;
    
    return authResponse;
;

exports.handler = (event, context, callback) => 

    console.log("Hit Authorizer")
    console.log(event)


    callback(null, generatePolicy('user123', 'Allow', event.methodArn));

; 

其他人看到过这个,或者知道如何调试它吗?

我把它放在一个测试网站上,只是有人想看看我所看到的。

https://s3.amazonaws.com/***isgreat2/index.html

【问题讨论】:

可以发一下授权人的内容吗? 添加了授权人 确保您的 statementOne.Resource = resource 具有这种格式“arn:aws:execute-api:us-west-2:123456789012:ymy8tbxw7b/*/GET/”。在您的情况下,允许所有内容为“arn:aws:execute-api:us-west-2:123456789012:ymy8tbxw7b/*/*/” Dung,我不确定你建议把它放在哪里。在 YAML 的 API 定义中?或在授权人中。 在您的授权人中,在“statementOne.Resource = resource;”行 【参考方案1】:

刚刚与 AWS 代表讨论了类似问题。手头的问题是 lambda 授权器缓存,它与 API 网关缓存不同。

默认情况下,您可能会缓存 lambda 授权方(见图),因此当您最初发出请求时,您的策略(特定于单一资源)会为 TTL 缓存。对使用相同 LAMBDA AUTHORIZER 的不同资源的后续请求将为您的原始资源返回相同的策略,这不是手头的资源,因此,您会得到 403。

将返回的策略更改为更通用的策略,如 @Dominic Nguyen 的回答是一种解决方案(通常涉及添加 /*s),但您也可以按照我的做法,在您的 lambda Authorizer 上禁用缓存:

然后,记得重新部署!!!代表告诉我在那之后等待 30 秒,然后进行测试。

【讨论】:

【参考方案2】:

在自定义授权人代码中,在行

statementOne.Resource = resource;

将您的资源更改为这种格式“arn:aws:execute-api:us-west-2:123456789012:ymy8tbxw7b/*/GET/”。

在你的情况下允许所有这些:

statementOne.Resource = arn:aws:execute-api:us-west-2:123456789012:ymy8tbxw7b/*/*/

这就是 AWS 理解您的授权人的方式。因为在自定义授权器中,您可以从请求标头中获取信息,例如用户、组等,然后根据您的授权数据库验证信息并决定允许谁或什么继续请求类型 POST/GET/OPTION,但 API 网关不会在您以 AWS 格式提供有效答案之前,您不会知道您的决定


  "principalId": "yyyyyyyy", // The principal user identification associated with the token sent by the client.
  "policyDocument": 
    "Version": "2012-10-17",
    "Statement": [
      
        "Action": "execute-api:Invoke",
        "Effect": "Allow|Deny",
        "Resource": "arn:aws:execute-api:regionId:accountId:appId/stage/httpVerb/[resource/[child-resources]]"
      
    ]
  ,
  "context": 
    "stringKey": "value",
    "numberKey": "1",
    "booleanKey": "true"
  ,
  "usageIdentifierKey": "api-key"  # Optional

您可以访问此页面以了解更多信息:

https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-lambda-authorizer-output.html

【讨论】:

以上是关于具有自定义授权者和 CORS 间歇性 200 然后 403 然后 200 的 AWS API 网关 ...奇怪的主要内容,如果未能解决你的问题,请参考以下文章

AWS 无服务器自定义 jwt 授权方 lambda 设置 cors 响应

具有 CAS 身份验证和自定义授权的 Spring Security

具有自定义授权的 JWT 和 KONG

从请求中剥离的 CORS 自定义标头

Spring Security 和 OAuth2 生成具有自定义授权类型的令牌

Hapi、Joi 和 Formdata 上传出现神秘的间歇性 CORS 错误