API Gateway 验证内容类型标头

Posted

技术标签:

【中文标题】API Gateway 验证内容类型标头【英文标题】:API Gateway validate content-type header 【发布时间】:2019-02-24 23:07:31 【问题描述】:

如果内容类型不是 json api 网关不进行验证,只是通过。我使用代理集成,所以没有映射模板,只能使用“when_no_match”。我正在使用内联招摇。

我可以检查标头是否存在但不检查值 - 我该怎么做?

/myMethod:
    post:
        x-amazon-apigateway-request-validator : "myvalidator"
        parameters:
        # How do I also validate Content-Type value is "application/json"
        - name: Content-Type
          in: header
          required: true

我希望 API 网关对此进行验证,因此我不必在代码中检查它

【问题讨论】:

您希望响应始终使用 application/json 吗? 我希望 API Gateway 拒绝对此方法的未将 content-type 设置为 application/json 的请求 您可以使用 Lambda@edge 轻松拒绝没有正确内容类型的请求。此外,这将比 API GW 中的更改更易于维护。 【参考方案1】:

转到端点的Integration Request 选项卡,单击Mapping Templates,将Request body passthrough 设置为never,为application/javascript 添加映射模板,然后从Generate template 旁边的下拉列表中单击Method Request Passthrough .

这是招摇的 sn-p: requestTemplates: application/json: | ## See http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html ## This template will pass through all parameters including path, querystring, header, stage variables, and context through to the integration endpoint via the body/payload #set($allParams = $input.params()) "body-json" : $input.json('$'), "params" : #foreach($type in $allParams.keySet()) #set($params = $allParams.get($type)) "$type" : #foreach($paramName in $params.keySet()) "$paramName" : "$util.escapeJavaScript($params.get($paramName))" #if($foreach.hasNext),#end #end #if($foreach.hasNext),#end #end , "stage-variables" : #foreach($key in $stageVariables.keySet()) "$key" : "$util.escapeJavaScript($stageVariables.get($key))" #if($foreach.hasNext),#end #end , "context" : "account-id" : "$context.identity.accountId", "api-id" : "$context.apiId", "api-key" : "$context.identity.apiKey", "authorizer-principal-id" : "$context.authorizer.principalId", "caller" : "$context.identity.caller", "cognito-authentication-provider" : "$context.identity.cognitoAuthenticationProvider", "cognito-authentication-type" : "$context.identity.cognitoAuthenticationType", "cognito-identity-id" : "$context.identity.cognitoIdentityId", "cognito-identity-pool-id" : "$context.identity.cognitoIdentityPoolId", "http-method" : "$context.httpMethod", "stage" : "$context.stage", "source-ip" : "$context.identity.sourceIp", "user" : "$context.identity.user", "user-agent" : "$context.identity.userAgent", "user-arn" : "$context.identity.userArn", "request-id" : "$context.requestId", "resource-id" : "$context.resourceId", "resource-path" : "$context.resourcePath" passthroughBehavior: "never" httpMethod: "POST" type: "aws"

【讨论】:

Mapping Templates 部分在使用代理集成时不可用。目前似乎没有办法通过代理集成拒绝基于标头值的请求。【参考方案2】:

因为我自己也在这么长时间后寻找答案,所以我发现涉及 swagger/openapi 规范文件的唯一解决方案是使用这个映射模板(这是我能想到的最短的):

#set($allParams = $input.params())
    
        "body" : $input.json('$'),
        #set($pathParams = $allParams.get('path'))
        "pathParameters" : 
            #foreach($paramName in $pathParams.keySet())
                "$paramName" : "$util.escapeJavaScript($pathParams.get($paramName))"
                #if($foreach.hasNext),#end
            #end
        ,
        #set($queryParams = $allParams.get('querystring'))
        "queryString" : 
            #foreach($paramName in $queryParams.keySet())
                "$paramName" : "$util.escapeJavaScript($queryParams.get($paramName))"
                #if($foreach.hasNext),#end
            #end
        
    

在我们想要应用它的规范路径中:

  paths:
    /your-path:
      x-amazon-apigateway-integration:
        credentials: "arn:aws:iam::xxx:role/yyy"
        uri: "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:zzz:function:qqq/invocations"
        responses:
          default:
            statusCode: 200
        passthroughBehavior: never
        httpMethod: POST
        requestTemplates:
          application/json: "#set($allParams = $input.params())\n        \n     \
        \       \"body\" : $input.json('$'),\n            #set($pathParams = $allParams.get('path'))\n\
        \            \"pathParameters\" : \n                #foreach($paramName\
        \ in $pathParams.keySet())\n                    \"$paramName\" : \"$util.escapeJavaScript($pathParams.get($paramName))\"\
        \n                    #if($foreach.hasNext),#end\n                #end\n\
        \            ,\n            #set($queryParams = $allParams.get('querystring'))\n\
        \            \"queryString\" : \n                #foreach($paramName\
        \ in $queryParams.keySet())\n                    \"$paramName\" : \"$util.escapeJavaScript($queryParams.get($paramName))\"\
        \n                    #if($foreach.hasNext),#end\n                #end\n\
        \            \n        "
        type: aws

不幸的是,这对我来说非常笨拙,我只是决定使用标准代理集成,并将请求验证设置为全部:

x-amazon-apigateway-request-validators: 
  all: 
    validateRequestBody: true,
    validateRequestParameters: true
  

x-amazon-apigateway-request-validator: all

【讨论】:

以上是关于API Gateway 验证内容类型标头的主要内容,如果未能解决你的问题,请参考以下文章

不同“接受”内容类型标头字段的不同身份验证

Postman API 无效的内容类型标头

带有标头和身份验证的 npm 请求

具有 Cognito 身份验证的 AWS API Gateway Lambda 函数返回 415 Unsupported Media Type

为啥在路由到 REST WebAPI 获取方法时需要内容类型标头?

AWS API Gateway按标头信息调用Lambda版本