在 Lambda 中获取用户的 IP 地址(使用 API Gateway 和 Python)

Posted

技术标签:

【中文标题】在 Lambda 中获取用户的 IP 地址(使用 API Gateway 和 Python)【英文标题】:Get user's IP Address in Lambda (with API Gateway, and Python) 【发布时间】:2021-08-18 23:35:50 【问题描述】:

我使用了这种技术 (How could I retrieve AWS Lambda public IP address by using Python?),但它提供了 AWS 内 Lambda 服务器的 IPAddress。

基于此:How can I retrieve a user's public IP address via Amazon API Gateway + Lambda (node),看来应该可以用了

ip_address = event['requestContext']['identity']['sourceIp'];

我的处理程序是这样开始的:

def lambda_handler(event, context):

但如果我执行pprint.pprint(event),我看不到任何 RequestContext,只有“正文”。

FFXSam 对 Jonathan 回答的最后一条评论说:“应该注意,如果您提供的页面不在授权方后面,则 event.requestContext.identity 不存在。”。 我不确定这意味着什么或为什么它是真的。我正在使用 API Gateway,并且客户端的 javascript 代码正在调用它。

我可以要求客户端编码器将正文中的本地 IP 地址发送给我,但似乎我应该能够在 Lambda 函数本身中获取它。

有人询问事件,尽管我说它只有在名为“body”的 json 元素中传递的字段:

代码:

print("pprint event:")
pprint.pprint(event)


2021-06-06T13:30:01.231-05:00   pprint event:
2021-06-06T13:30:01.231-05:00   'body': 'ResponseTimeMilliseconds': 2225,
2021-06-06T13:30:01.231-05:00   'authToken': '12312312',
2021-06-06T13:30:01.231-05:00   'handNumber': 7

【问题讨论】:

检查您是否通过aws apigateway get-authorizers --rest-api-id YOUR-API-ID在API网关中或在授权者部分下的控制台中附加了授权者 @JenyaY。 - 没有授权人 如果我添加一个“授权人”,这意味着客户端代码必须更改,对吗?添加授权人是否会自动使 IP 地址起作用,如果是,为什么? 阅读您链接的帖子中的第二个答案:***.com/a/46021715/13070 另请注意,它完全取决于您选择的 API Gateway 集成类型,以及您拥有的映射模板或请求直通选项选择。您的问题实际上是另一个问题的重复。您需要花时间阅读完整的答案,包括有关映射模板的信息。 MarkB - 我在 events 对象上做了一个 pprint,但在那里没有看到类似的东西。当我有机会时,我会再次检查。看起来上下文可能已经想到了,其他答案之一:$context.identity.sourceIp 【参考方案1】:

我奖励了 Muzaffar Shaikh,但在这里我将给出更彻底的解释,这似乎是 *** 所缺乏的。他的回答得到了 IP 地址,但删除了我的“body”字段,但它确实为我指明了正确的方向。

在 AWS API Gateway 工具中,单击“资源”,然后单击您的方法(我的是“发布”),然后单击“集成请求”,如图所示。

向下滚动到底部,如果没有任何模板,请输入“application/json”并单击复选框(注意,“application/json”以浅灰色字母出现,但只需单击复选框而不输入它不起作用)。

然后我输入以下模板:


   "client_ip" : "$input.params('X-Forwarded-For')",
   "user_agent" : "$input.params('User-Agent')",
   "body" : $input.json('$.body') 

注意:如果我输入 $input.json('$') 或 $input.json('body'),我最终会在我的“body”字段中添加一个“body”字段,这破坏了当前的逻辑。

网页完成后是这样的:

下一步是将模板重新部署到您正在使用的“部署阶段”(环境)。

顺便说一下,在输入模板的时候,如果在“生成模板”下拉框中点击“方法请求透传”,就会生成这样的模板(我没用这个选项,但是会阅读更多很快就知道了):

##  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"
    

映射模板的两个参考:

    https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html https://docs.aws.amazon.com/apigateway/latest/developerguide/models-mappings.html

关于何时使用“$input.params”和“$context.some_value”,我还有一些研究要做。

【讨论】:

【参考方案2】:

你可以试试这个:

    将 X-Forwarded-For 添加到“HTTP 请求标头”(转到 API-Gateway 配置 -> 资源 -> 方法请求)。 添加 Content-Type 的模板:application/json(资源 -> 集成请求 -> “映射模板”) 向模板添加映射

   "client_ip" : "$input.params('X-Forwarded-For')",
   "user_agent" : "$input.params('User-Agent')"

    现在 Lambda 中的标头可以按预期使用:

event.client_ip

你也可以参考这个链接: https://forums.aws.amazon.com/thread.jspa?messageID=648053

【讨论】:

谢谢,我认为这让我走上了正确的道路。在我让它工作后,我会奖励赏金。我现在的问题是:***.com/questions/67872825/…,我失去了现有的“身体”并试图弄清楚如何将其放回原处。 我给了你赏金,但通过一些屏幕截图以及如何让“身体”继续工作,给出了更完整的答案。【参考方案3】:

我花了一段时间不知道如何在我的集成请求中添加映射模板。不知道发生了什么,但对于任何绊倒我的人来说,我所做的是:

选中集成请求中的使用 Lambda 代理集成复选框。

现在我可以使用 event.["headers"] 在 Python lambda 函数中非常轻松地访问我的标头。

添加截图方便查找:

在您的 API 的相关方法中转到集成请求。 (请参阅我如何在 Method Request 中添加 X-Forwarded-For 标头,如其他答案中所建议的那样)

复选框在这里:

(我不必制作映射模板。真的不知道这里发生了什么。)

【讨论】:

你做的截图会非常有用,谢谢。

以上是关于在 Lambda 中获取用户的 IP 地址(使用 API Gateway 和 Python)的主要内容,如果未能解决你的问题,请参考以下文章

有啥方法可以在nodejs中获取用户请求的内部IP地址

无论如何,是不是可以使用 lambda 自动将新 IP 地址分配给入站规则中的安全组

使用 AWS api 网关 + lambda + Nodejs 的私有和公共 ip

如何在C#中获取用户的公共IP地址

如何在 Symfony2 控制器中获取用户 IP 地址?

Java中使用HttpRequest获取用户真实IP地址端口