Python/Django中如何正确获取当前登录用户的真实IP地址
问题根源
你最初使用的socket库相关方法,作用是读取运行代码的服务器自身的主机名和绑定IP,本地开发时你的电脑同时承担客户端、服务端角色,所以返回结果看起来符合预期;项目部署到线上服务器后,服务端和访问用户的客户端分属不同设备,该方法自然只能返回线上服务器自身的信息,不可能拿到访问用户的端侧数据。
正确实现思路
用户的访问IP是通过HTTP请求携带的,你需要从Web框架接收到的请求对象中提取对应字段,不要用服务器本地socket方法查询。另外要注意:公网场景下几乎无法准确获取用户端本地设置的主机名——HTTP协议不会主动透传用户设备的本地主机名,对用户IP做反向解析的结果绝大多数是运营商网关域名,和用户实际主机名无关,建议不要把用户主机名作为核心业务依赖字段。
不同Web框架的代码实现
首先要注意:如果你的服务前面挂了Nginx、CDN、云负载均衡等反向代理层,需要先在代理层配置规则,把用户真实IP透传到后端服务,否则后端拿到的永远是代理节点的IP。
- Flask 框架示例
import socket from flask import request @app.route('/login', methods=['POST']) def login(): # 优先取反代透传的真实IP,无反代时取直连IP if request.headers.get('X-Forwarded-For'): # X-Forwarded-For 格式为 [用户真实IP, 一级代理IP, 二级代理IP...],取第一个非空值即可 user_ip = request.headers.get('X-Forwarded-For').split(',')[0].strip() else: user_ip = request.remote_addr # 尝试反向解析主机名,必须加异常兜底,大部分场景会解析失败 try: user_hostname = socket.gethostbyaddr(user_ip)[0] except: user_hostname = "未知" # 后续登录业务逻辑
- Django 框架示例
import socket def login(request): if request.META.get('HTTP_X_FORWARDED_FOR'): user_ip = request.META.get('HTTP_X_FORWARDED_FOR').split(',')[0].strip() else: user_ip = request.META.get('REMOTE_ADDR') # 主机名解析逻辑同上,做好失败兜底 try: user_hostname = socket.gethostbyaddr(user_ip)[0] except: user_hostname = "未知" # 后续登录业务逻辑
反向代理配置参考(Nginx)
如果用Nginx做反向代理,需要在配置中增加透传规则,否则后端无法拿到真实用户IP:
location / { proxy_pass http://你的后端服务监听地址; proxy_set_header X-Forwarded-For $remote_addr; }
关键注意事项
- 不要信任前端主动传入的IP参数,所有IP字段必须从服务端接收到的原始请求头中提取,避免用户伪造IP绕过业务校验
- 多层代理场景下,需要确认最外层代理已经正确把用户真实IP写入
X-Forwarded-For字段的第一位,避免取到中间代理的IP - 用户主机名字段解析成功率极低,仅作辅助信息使用,不要作为登录校验、风控判断的核心依据
内容的提问来源于stack exchange,提问作者Ibrahim Khan
相关产品推荐
相关产品推荐

