如何确保仅针对特定路径调用 API 网关令牌授权方
How to make sure the API Gateway token authorizer is invoked only for specific paths
我们有一个使用自定义 令牌授权者 的 API 网关。我们有 2 个 lambda - Greetings 和 GenerateToken.
我们只希望 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
我们有一个使用自定义 令牌授权者 的 API 网关。我们有 2 个 lambda - Greetings 和 GenerateToken.
我们只希望 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