问题
I have an 1 Amazon Api Gateway setup with a custom authorizer (the authorizer basically just returns allow for anything)
I enabled CORS, and this is running from jQuery webpage.
I have two method
- /vehicles (returns a list of car)
- /bookings (returns booking details)
The behavior I am seeing, is the first request goes fine, I see it pull the OPTIONS, then perform a GET request. Then, I hit the other method the OPTIONS works, then the get returns a 403, but if I launch the request again (On the same resource), I get a 200
I'm using Cloudformation, but I noticed the same behaviour when I was using the Serverless Framework.
Below are some screen shots for my sanity and hopefully someone else has seen this strangeness.
Below is a portion of my Cloudformation YAML template, I'm learning this as I do it.
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"
This is my 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));
};
Anyone else seen this, or know how to debug it ?
I put this on a test site, just it some one wants to see what I am seeing.
https://s3.amazonaws.com/stackoverflowisgreat2/index.html
回答1:
In the custom authorizer code, at the line
statementOne.Resource = resource;
change your resources to this format "arn:aws:execute-api:us-west-2:123456789012:ymy8tbxw7b/*/GET/".
In your case to allow all that would be:
statementOne.Resource = arn:aws:execute-api:us-west-2:123456789012:ymy8tbxw7b/*/*/
This is how AWS understands your authorizer. Because in custom authorizer you can get information from the request header like user, group, etc and then validate the info against your authorization database and decide who or what is allowed to continue the request type POST/GET/OPTION, but API gateway won't know your decision until you provide it with a valid answer in AWS format
{
"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
}
You can visit this page to understand more about it:
https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-lambda-authorizer-output.html
回答2:
Just talked with an AWS rep about a similar issue. The issue at hand is lambda authorizer caching, which is different than API Gateway caching.
You likely have your lambda authorizer caching by default (see photo), so when you initially make a request, your policy (which is specific to a singular resource), gets cached for the TTL. Subsequent requests to DIFFERENT RESOURCES which use the SAME LAMBDA AUTHORIZER will return the SAME POLICY for your original resource, which is not the resource at hand, and as a result, you get a 403.
Changing the returned policy to something more general a la @Dominic Nguyen's answer is one solution (usually involves adding /*s), but you can also do what I did and just disable caching on your lambda Authorizer:
Then, REMEMBER to REDEPLOY!!! Rep told me to wait 30 seconds after that, then test.
来源:https://stackoverflow.com/questions/51549637/aws-api-gateway-with-custom-authorizer-and-cors-intermittent-200-then-403-then-2