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

时间:2018-07-27 01:37:31

标签: amazon-web-services cors aws-api-gateway amazon-cloudformation

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

我启用了CORS,并且正在 jQuery 网页上运行。

我有两种方法

  1. /车辆(返回汽车清单)
  2. /预订(返回预订详细信息)

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

我正在使用Cloudformation,但是当我使用无服务器框架时,我注意到了相同的行为。

下面是我的理智的一些屏幕截图,希望其他人已经看到了这种陌生感。

enter image description here

enter image description here

以下是我的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"

这是我的一切授权人

'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/stackoverflowisgreat2/index.html

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

只需与AWS代表讨论类似问题。当前的问题是lambda授权者缓存,这与API Gateway缓存不同。

默认情况下,您可能会对lambda授权者进行缓存(参见照片),因此,当您最初发出请求时,您的策略(特定于单个资源)将被缓存为TTL。随后对使用SAME LAMBDA AUTHORIZER的不同资源的请求将返回原始资源(不是手头的资源)的SAME POLICY,因此,您得到403。

将返回的策略更改为更一般的方式,例如@Dominic Nguyen的答案是一种解决方案(通常涉及添加/ * s),但是您也可以执行我的操作,而只是禁用对lambda Authorizer的缓存:

lambda authorizer cache settings 然后,请记住重新部署!!! Rep告诉我在那之后等待30秒,然后进行测试。