如何确保仅针对特定路径调用 API 网关令牌授权方

How to make sure the API Gateway token authorizer is invoked only for specific paths

我们有一个使用自定义 令牌授权者 的 API 网关。我们有 2 个 lambda - GreetingsGenerateToken.

我们只希望 Greetings lambda 位于授权者之后 - 需要使用 SAM 按以下方式调用:

curl -X GET \
  https://<apigatewayid>.execute-api.eu-west-1.amazonaws.com/Prod/generateToken \
  -H 'X-API-KEY: allow'

我们如何实现 GenerateToken 路径不需要 HTTP 令牌进行身份验证?

AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: API Gateway with Lambda Token Authorizer
Resources:
  GreetingsApiGateway:
    Type: AWS::Serverless::Api
    Properties:
      StageName: Prod
      DefinitionBody:
        swagger: 2.0
        x-amazon-apigateway-policy:
          Version: "2012-10-17"
          Statement:
            - Effect: Allow
              Principal: "*"
              Action: execute-api:Invoke
              Resource:
                - execute-api:/*/*/*
        paths:
          "/hello":
            get:
              x-amazon-apigateway-integration:
                httpMethod: POST
                type: aws_proxy
                uri:
                  Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GreetingsLambda.Arn}/invocations
              responses: {}
          "/generateToken":
            get:
              x-amazon-apigateway-integration:
                httpMethod: POST
                type: aws_proxy
                uri:
                  Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GenerateTokenLambda.Arn}/invocations
              responses: {}
      Auth:
        DefaultAuthorizer: CustomAuthorizer
        Authorizers:
          MyAuthorizer:
            FunctionArn: !GetAtt AuthLambda.Arn
            Identity:
              Header: X-API-KEY

  GenerateTokenLambda:
    Type: AWS::Serverless::Function
    Properties:
      Role: !GetAtt LambdaRole.Arn
      CodeUri: "s3://<bucket-name>/code.zip"
      Handler: src/generateToken.handler
      Events:
        GetRoot:
          Type: Api
          Properties:
            RestApiId: !Ref GreetingsApiGateway
            Path: /generateToken
            Method: get

  GreetingsLambda:
    Type: AWS::Serverless::Function
    Properties:
      Role: !GetAtt LambdaRole.Arn
      CodeUri: "s3://<bucket-name>/code.zip"
      Handler: src/greetings.handler
      Events:
        GetRoot:
          Type: Api
          Properties:
            RestApiId: !Ref GreetingsApiGateway
            Path: /hello
            Method: get

  AuthLambda:
    Type: AWS::Serverless::Function
    Properties:
      Role: !GetAtt LambdaRole.Arn
      CodeUri: "s3://<bucket-name>/code.zip"
      Handler: src/auth.handler

Globals:
  Function:
    Runtime: nodejs8.10

Outputs:
  ApiURL:
    Description: "OUR API URL"
    Value: !Sub "https://${GreetingsApiGateway}.execute-api.${AWS::Region}.amazonaws.com/Prod/"

我不太确定我是否完全理解您想要什么,但这里有一个 Cloudformation 模板,用于创建 api-gateway 启用和未启用授权的资源。我正在使用 Cognito User Pool 授权方法,但它可以很容易地成为自定义授权方。

RestAPI:
  Type: AWS::ApiGateway::RestApi
  DeletionPolicy: Delete
  Properties:
    Name: {"Ref": "AWS::StackName"}
    ApiKeySourceType: HEADER
    EndpointConfiguration:
      Types:
        - EDGE

ApiAuthorizer:
  Type: AWS::ApiGateway::Authorizer
  DeletionPolicy: Retain
  DependsOn: UserPoolList
  Properties:
    Name: !Join ["-", [{"Ref": "AWS::StackName"}, "authorizer"]]
    RestApiId: !Ref RestAPI
    Type: COGNITO_USER_POOLS
    AuthType: cognito_user_pools
    IdentitySource: "method.request.header.Authorization"
    ProviderARNs: <User Pool ARN>

ResourceSignin:
  Type: AWS::ApiGateway::Resource
  DeletionPolicy: Delete
  Properties:
    RestApiId: !Ref RestAPI
    ParentId: !GetAtt RestAPI.RootResourceId
    PathPart: "signin"

SigninPostMethod:
  Type: AWS::ApiGateway::Method
  Properties:
    RestApiId: !Ref RestAPI
    ResourceId: !Ref ResourceSignin
    HttpMethod: POST
    AuthorizationType: NONE
    ApiKeyRequired: <true/false>
    Integration:
      Type: AWS_PROXY
      IntegrationHttpMethod: POST
      Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${UserHandlerFunction.Arn}/invocations
      Credentials: !GetAtt GenApiGatewayRole.Arn

ResourceUserCreate:
  Type: AWS::ApiGateway::Resource
  DeletionPolicy: Delete
  Properties:
    RestApiId: !Ref RestAPI
    ParentId: !GetAtt RestAPI.RootResourceId
    PathPart: "create"

CreatePostMethod:
  Type: AWS::ApiGateway::Method
  Properties:
    RestApiId: !Ref RestAPI
    ResourceId: !Ref ResourceUserCreate
    HttpMethod: POST
    AuthorizationType: COGNITO_USER_POOLS
    AuthorizerId: !Ref ApiAuthorizer
    ApiKeyRequired: <true/false>
    Integration:
      Type: AWS_PROXY
      IntegrationHttpMethod: POST
      Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${UserHandlerFunction.Arn}/invocations
      Credentials: !GetAtt UserApiGatewayRole.Arn

此处资源 signin 有一个 POST 方法没有授权,而 create 资源有一个 POST 方法启用了授权。

如果您打算使用 API keys,这可能是唯一可行的方法。我无法让 API keys 与 SAM 一起工作(我相信 API keys 与 SAM 尚不支持 - 这是大约一个月前的事,但你可以仔细检查)。

我们可以在 API 网关中通过招摇来实现这一点:

World lambda 是一个 public API 而 Hello lambda 位于 AuthLambda 授权方之后


  OurApiGateway:
    Type: AWS::Serverless::Api
    Properties:
      StageName: Prod
      Auth:
        Authorizers:
          MyAuthorizer:
            FunctionPayloadType: REQUEST
            FunctionArn: !GetAtt AuthLambda.Arn
      DefinitionBody:
        swagger: 2.0
        basePath: /prod
        info:
          title: AwsSamExample
        x-amazon-apigateway-policy:
          Version: "2012-10-17"
          Statement:
            - Effect: Allow
              Principal: "*"
              Action: execute-api:Invoke
              Resource:
                - execute-api:/*/*/*
        schemes:
          - https
        paths:
          "/hello":
            get:
              x-amazon-apigateway-integration:
                httpMethod: POST
                type: aws_proxy
                uri:
                  Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HelloLambda.Arn}/invocations
              responses: {}
              security:
                - MyAuthorizer: []
          "/world":
            get:
              x-amazon-apigateway-integration:
                httpMethod: POST
                type: aws_proxy
                uri:
                  Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${WorldLambda.Arn}/invocations
              responses: {}
              security: []


使用无服务器框架,只需一个属性即可轻松管理它。 https://www.npmjs.com/package/serverless