如何在django中获取用户IP地址?

如何在django中获取用户的IP?

我有这样的看法:

# Create your views from django.contrib.gis.utils import GeoIP from django.template import RequestContext from django.shortcuts import render_to_response def home(request): g = GeoIP() client_ip = request.META['REMOTE_ADDR'] lat,long = g.lat_lon(client_ip) return render_to_response('home_page_tmp.html',locals()) 

但是我得到这个错误:

 KeyError at /mypage/ 'REMOTE_ADDR' Request Method: GET Request URL: http://mywebsite.com/mypage/ Django Version: 1.2.4 Exception Type: KeyError Exception Value: 'REMOTE_ADDR' Exception Location: /mysite/homepage/views.py in home, line 9 Python Executable: /usr/bin/python Python Version: 2.6.6 Python Path: ['/mysite', '/usr/local/lib/python2.6/dist-packages/flup-1.0.2-py2.6.egg', '/usr/lib/python2.6', '/usr/lib/python2.6/plat-linux2', '/usr/lib/python2.6/lib-tk', '/usr/lib/python2.6/lib-old', '/usr/lib/python2.6/lib-dynload', '/usr/local/lib/python2.6/dist-packages', '/usr/lib/python2.6/dist-packages', '/usr/lib/pymodules/python2.6'] Server time: Sun, 2 Jan 2011 20:42:50 -0600 
 def get_client_ip(request): x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') if x_forwarded_for: ip = x_forwarded_for.split(',')[0] else: ip = request.META.get('REMOTE_ADDR') return ip 

确保你有反向代理(如果有的话)configuration正确(例如mod_rpaf为Apache安装)。

注意:以上使用的是X-Forwarded-For第一个项目,但是您可能想要使用最后一个项目(例如,在Heroku的情况下:在Heroku上获取客户端的真实IP地址 )

然后把请求作为parameter passing给它;

 get_client_ip(request) 

您可以保持干爽 ,只需使用支持IPv4IPv6以及Python 3的 django-ipware

安装:

 pip install django-ipware 

在您的视图或中间件中:

 from ipware.ip import get_ip ip = get_ip(request) if ip is not None: print("we have an IP address for user") else: print("we don't have an IP address for user") 

它会尝试获取用户的IP地址,或返回None来表示无法确定用户的IP地址。

更新:(高级用户)

ipware => 1.1.5增加了对受信任代理服务器configuration的支持。

 # Requirements: Your web server is behind one or more proxy server(s). # Proxy server(s) set either `HTTP_X_FORWARDED_FOR` or `X_FORWARDED_FOR` header attributes. from ipware.ip import get_trusted_ip ip = get_trusted_ip(request, trusted_proxies=['23.91.45.15']) if ip is not None: print("we got user's real IP address from a known proxy") else: print("request wasn't from a unknown proxy. Not a trusted IP.") # if you still need an ip address then use `get_ip()`, knowing that it may # be fake. (aka spoofed) 

亚历山大的答案很好,但是缺乏对HTTP_X_FORWARDED_FOR头中有时返回多个IP的代理的处理。

真正的IP通常在列表的末尾,如下所述: http : //en.wikipedia.org/wiki/X-Forwarded-For

解决方法是对Alexander的代码进行简单的修改:

 def get_client_ip(request): x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') if x_forwarded_for: ip = x_forwarded_for.split(',')[-1].strip() else: ip = request.META.get('REMOTE_ADDR') return ip 

我想build议改善yanchenko的答案。

而不是在X_FORWARDED_FOR列表中的第一个IP,我采取了第一个在不知名的内部IP,因为有些路由器不尊重协议,你可以看到内部ips作为列表的第一个值。

 PRIVATE_IPS_PREFIX = ('10.', '172.', '192.', ) def get_client_ip(request): """get the client ip from the request """ remote_address = request.META.get('REMOTE_ADDR') # set the default value of the ip to be the REMOTE_ADDR if available # else None ip = remote_address # try to get the first non-proxy ip (not a private ip) from the # HTTP_X_FORWARDED_FOR x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') if x_forwarded_for: proxies = x_forwarded_for.split(',') # remove the private ips from the beginning while (len(proxies) > 0 and proxies[0].startswith(PRIVATE_IPS_PREFIX)): proxies.pop(0) # take the first ip which is not a private one (of a proxy) if len(proxies) > 0: ip = proxies[0] return ip 

我希望这可以帮助有同样问题的Google员工。

最简单的解决scheme(如果你使用fastcgi + nignx)是itgorilla所评论的:

谢谢你这个好问题 我的fastcgi没有通过REMOTE_ADDR元键。 我在nginx.conf中添加了下面这行,并解决了这个问题:fastcgi_param REMOTE_ADDR $ remote_addr; – itgorilla

Ps:我加了这个答案只是为了让他的解决scheme更加明显。

在我的情况下,以上都没有工作,所以我必须检查uwsgi + django源代码并在nginx中传递静态参数,看看为什么/如何,以下是我发现的。

Env信息:
python版本: 2.7.5
Django版本: (1, 6, 6, 'final', 0) 1,6,6 (1, 6, 6, 'final', 0)
nginx版本: nginx/1.6.0
uwsgi: 2.0.7

Env设置信息:
nginx作为反向代理监听端口80 uwsgi作为上游的unix socket,最终会响应请求

Djangoconfiguration信息:

 USE_X_FORWARDED_HOST = True # with or without this line does not matter 

nginxconfiguration:

 uwsgi_param X-Real-IP $remote_addr; // uwsgi_param X-Forwarded-For $proxy_add_x_forwarded_for; // uwsgi_param HTTP_X_FORWARDED_FOR $proxy_add_x_forwarded_for; // hardcode for testing uwsgi_param X-Forwarded-For "10.10.10.10"; uwsgi_param HTTP_X_FORWARDED_FOR "20.20.20.20"; 

得到Django应用程序中的所有参数:

 X-Forwarded-For : 10.10.10.10 HTTP_X_FORWARDED_FOR : 20.20.20.20 

结论:

所以基本上,你必须在nginx中指定完全相同的字段/参数名称,并在django应用程序中使用request.META[field/param]

现在你可以决定是否添加一个中间件(拦截器),或者只是在某些视图中parsingHTTP_X_FORWARDED_FOR

从Django中删除function的原因最初是头不能最终被信任。 原因是这很容易欺骗。 例如,configurationnginx反向代理的推荐方法是:

 add_header X-Forwarded-For $proxy_add_x_forwarded_for; add_header X-Real-Ip $remote_addr; 

当你这样做时:

 curl -H 'X-Forwarded-For: 8.8.8.8, 192.168.1.2' http://192.168.1.3/ 

您的myhost.com中的nginx将会发送:

 X-Forwarded-For: 8.8.8.8, 192.168.1.2, 192.168.1.3 

如果您盲目地按照说明进行操作,则X-Real-IP将成为第一个代理的IP。

如果信任你的用户是一个问题,你可以尝试类似django-xff : https : django-xff

我在上面的答案也失去了代理。 我使用了get_ip_address_from_request的get_ip_address_from_request 。

 from easy_timezones.utils import get_ip_address_from_request, is_valid_ip, is_local_ip ip = get_ip_address_from_request(request) try: if is_valid_ip(ip): geoip_record = IpRange.objects.by_ip(ip) except IpRange.DoesNotExist: return None 

这里是方法get_ip_address_from_request ,IPv4和IPv6就绪:

 def get_ip_address_from_request(request): """ Makes the best attempt to get the client's real IP or return the loopback """ PRIVATE_IPS_PREFIX = ('10.', '172.', '192.', '127.') ip_address = '' x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR', '') if x_forwarded_for and ',' not in x_forwarded_for: if not x_forwarded_for.startswith(PRIVATE_IPS_PREFIX) and is_valid_ip(x_forwarded_for): ip_address = x_forwarded_for.strip() else: ips = [ip.strip() for ip in x_forwarded_for.split(',')] for ip in ips: if ip.startswith(PRIVATE_IPS_PREFIX): continue elif not is_valid_ip(ip): continue else: ip_address = ip break if not ip_address: x_real_ip = request.META.get('HTTP_X_REAL_IP', '') if x_real_ip: if not x_real_ip.startswith(PRIVATE_IPS_PREFIX) and is_valid_ip(x_real_ip): ip_address = x_real_ip.strip() if not ip_address: remote_addr = request.META.get('REMOTE_ADDR', '') if remote_addr: if not remote_addr.startswith(PRIVATE_IPS_PREFIX) and is_valid_ip(remote_addr): ip_address = remote_addr.strip() if not ip_address: ip_address = '127.0.0.1' return ip_address 

request.META.get('REMOTE_ADDR')在这里就足够了。

这里是一个简短的一行来完成这个工作:

 request.META.get('HTTP_X_FORWARDED_FOR', request.META.get('REMOTE_ADDR')).split(',')[-1].strip() 

最简单的解决scheme是:

 from ipaddress import ip_address 

然后像这样使用它:

 print(get_client_ip(request))