我正在为某些lamba和授权者使用AWS SAM。确认API网关正在使用Postman(而不是控制台中的测试功能)使用授权者,并确认日志显示在授权者功能中。尚未对授权者进行任何花哨的操作,只是在令牌无效或丢失的情况下尝试传递回动态生成的WWW-Authenticate标头(现在仅作为示例来处理Authorization: bearer
[承载后无文本])
整个周末,我一直在撞墙,似乎无法让授权者传递上下文的任何值。我已经尝试了多种方法,例如$context.authorizer.challenge
和$event.requestContext.authorizer.challenge
,将它们放在正文和标头中,甚至尝试了$context.authorizer.principalId
也不产生任何东西。
处理请求的授权者代码:
func (a *authHandler) Handler(request events.APIGatewayCustomAuthorizerRequest) (events.APIGatewayCustomAuthorizerResponse, error) {
fmt.Printf("checking auth\n")
token := request.AuthorizationToken
tokenSlice := strings.Split(token, " ")
var bearerToken string
if len(tokenSlice) > 1 {
bearerToken = tokenSlice[len(tokenSlice)-1]
}
if bearerToken == "" {
fmt.Printf("about to return policy for empty token")
// I've tried multiple combinations of Deny/Allow, context maps, error response, etc.
return generatePolicy("user", "Deny", request.MethodArn, map[string]interface{}{"challenge": "testing"}), errors.New("Unauthorized")
}
return generatePolicy("user", "Allow", request.MethodArn, map[string]interface{}{"name": bearerToken}), nil
}
func generatePolicy(principalID, effect, resource string, context map[string]interface{}) events.APIGatewayCustomAuthorizerResponse {
authResponse := events.APIGatewayCustomAuthorizerResponse{PrincipalID: principalID}
if effect != "" && resource != "" {
authResponse.PolicyDocument = events.APIGatewayCustomAuthorizerPolicy{
Version: "2012-10-17",
Statement: []events.IAMPolicyStatement{
{
Action: []string{"execute-api:Invoke"},
Effect: effect,
Resource: []string{resource},
},
},
}
}
authResponse.Context = context
return authResponse
}
这只是一个占位符,如果收到Unauthorized
之类的空令牌承载,应该返回Authorization: bearer
。
template.yaml:
Resources:
BaseApi:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
Auth:
DefaultAuthorizer: TokenAuthorizer
Authorizers:
TokenAuthorizer:
FunctionPayloadType: TOKEN
FunctionArn: !GetAtt AuthTokenFunction.Arn
Identity:
Headers:
GatewayResponses:
UNAUTHORIZED:
StatusCode: 401
ResponseParameters:
Headers:
Access-Control-Expose-Headers: "'WWW-Authenticate'"
WWW-Authenticate: "context.authorizer.challenge"
Principal-ID: "context.authorizer.principalId"
ResponseTemplates:
"application/json": '{ "message": $context.error.messageString, "testing": "test", "challenge": $context.authorizer.challenge, "challengeEvent": $event.requestContext.authorizer.challenge }'
AuthTokenFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: cmd/lambda/auth
Handler: services-auth
Runtime: go1.x
Role: !GetAtt ParameterAuthTokenFunctionRole.Arn
Tracing: Active
Environment:
Variables:
APP_CONFIG_PATH: 'parameterAuthToken'
AWS_XRAY_TRACING_NAME: 'AuthTokenFunction'
ParameterAuthTokenFunctionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
-
Effect: Allow
Principal:
Service:
- 'lambda.amazonaws.com'
Action:
- 'sts:AssumeRole'
ManagedPolicyArns:
- 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'
Policies:
-
PolicyName: 'ParameterAuthTokenParameterAccess'
PolicyDocument:
Version: '2012-10-17'
Statement:
-
Effect: Allow
Action:
- 'ssm:GetParameter*'
#Resource: !Sub 'arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/prod/parameterAuthToken*'
Resource: '*'
-
PolicyName: 'ParameterAuthTokenXRayAccess'
PolicyDocument:
Version: '2012-10-17'
Statement:
-
Effect: Allow
Action:
- 'xray:PutTraceSegments'
- 'xray:PutTelemetryRecords'
Resource: '*'
ParameterAuthTokenEncryptionKeyAlias:
Type: AWS::KMS::Alias
Properties:
AliasName: 'alias/ParameterAuthTokenKey'
TargetKeyId: !Ref ParameterAuthTokenEncryptionKey
ParameterAuthTokenEncryptionKey:
Type: AWS::KMS::Key
Properties:
Description: 'Encryption key for secret config values for the Parameter Auth Token'
Enabled: True
EnableKeyRotation: False
KeyPolicy:
Version: '2012-10-17'
Id: 'key-default-1'
Statement:
-
Sid: 'Allow administration of the key & encryption of new values'
Effect: Allow
Principal:
AWS:
- !Sub 'arn:aws:iam::${AWS::AccountId}:user/anthony-local'
Action:
- 'kms:Create*'
- 'kms:Encrypt'
- 'kms:Describe*'
- 'kms:Enable*'
- 'kms:List*'
- 'kms:Put*'
- 'kms:Update*'
- 'kms:Revoke*'
- 'kms:Disable*'
- 'kms:Get*'
- 'kms:Delete*'
- 'kms:ScheduleKeyDeletion'
- 'kms:CancelKeyDeletion'
Resource: '*'
-
Sid: 'Allow use of the key'
Effect: Allow
Principal:
AWS: !GetAtt ParameterAuthTokenFunctionRole.Arn
Action:
- 'kms:Encrypt'
- 'kms:Decrypt'
- 'kms:ReEncrypt*'
- 'kms:GenerateDataKey*'
- 'kms:DescribeKey'
Resource: '*'
GhostFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: cmd/lambda/ghost
Handler: services-ghost
Runtime: go1.x
Tracing: Active
Events:
GetGhost:
Type: Api
Properties:
Path: /ghost/{id}
Method: GET
RestApiId: !Ref BaseApi
Auth:
Authorizer: TokenAuthorizer
响应:
401 Unauthorized
Headers:
WWW-Authenticate:
Principal-ID:
Access-Control-Expose-Headers: WWW-Authenticate
x-amzn-ErrorType: UnauthorizedException
Body:
{ "message": "Unauthorized", "testing": "test", "challenge": , "challengeEvent": }
以及一些控制台屏幕截图:
有任何线索吗?我将放弃w / authorizer,并在每个lambda函数本身中添加自己的逻辑。似乎更容易进行诸如应用标头的操作。
答案 0 :(得分:0)
扔掉毛巾,说这目前是不可能的,至少对于golang来说是不可能的。
如果我没有返回错误,则能够显示上下文。因此上下文出现在这里:
return generatePolicy("user", "Deny", request.MethodArn, map[string]interface{}{"challenge": "testing"}), nil
当我在aws控制台中调用auth lambda时,可以看到它。问题似乎是您不能同时传递策略信息和错误。因此上下文永远不会出现在响应模板中。
此外,如此thread所示,其他人也无法通过其中任何一个获取自定义的WWW-Authenticate
标头。使用golang库,似乎都不可能通过任何一种获得自定义HTTP错误代码。因此,我无法将402 Payment Required
与WWW-Authenticate
标头一起使用的计划。
解决方案:
保留授权者,在其中处理auth逻辑,但将质询传递给lambda。
return generatePolicy("user", "Allow", request.MethodArn, map[string]interface{}{"challenge": "testing"}), nil
并通过$event.requestContext.authorizer.challenge
在上下文中读取我要与此授权程序耦合的每个lambda,并以这种方式处理标头的402响应。绝对不理想,但是在授权者可以被定制得足以进行标准化之前,我认为这必须是中间立场。