如何在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)
您可以保持干爽 ,只需使用支持IPv4和IPv6以及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))