Comment obtenir l'adresse IP d'un utilisateur à django?
Comment obtenir L'adresse IP d'un utilisateur à django?
j'ai une vue comme celle-ci:
# 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())
mais je reçois cette erreur:
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
10 réponses
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
assurez-vous que vous avez le proxy inversé (le cas échéant) configuré correctement (par exemple mod_rpaf
installé pour Apache).
Note: ce qui précède utilise le premier article dans X-Forwarded-For
, mais vous pourriez vouloir utiliser le dernier article (par exemple, dans le cas de Heroku: obtenir l'adresse IP réelle du client sur Heroku )
et puis passer la requête comme argument à elle;
get_client_ip(request)
vous pouvez utiliser django-ipware qui supporte Python 2 & 3 et manipule IPv4 & IPv6 .
Installation:
pip install django-ipware
Usage Simple:
pour obtenir l'adresse IP du client.
# In a view or a middleware where the `request` object is available
from ipware import get_client_ip
ip, is_routable = get_client_ip(request)
if ip is None:
# Unable to get the client's IP address
else:
# We got the client's IP address
if is_routable:
# The client's IP address is publicly routable on the Internet
else:
# The client's IP address is private
# Order of precedence is (Public, Private, Loopback, None)
Usage Avancé:
en-tête personnalisé-en-tête de requête personnalisé pour ipware à regarder
i, r = get_client_ip(request, request_header_order=['X_FORWARDED_FOR'])
i, r = get_client_ip(request, request_header_order=['X_FORWARDED_FOR', 'REMOTE_ADDR'])
compte de mandataire-Django server est derrière un nombre fixe de procurations
i, r = get_client_ip(request, proxy_count=1)
de Confiance des Procurations - Django serveur est derrière un ou plus connue et de confiance des proxies
i, r = get_client_ip(request, proxy_trusted_ips=('177.2.2.2'))
# For multiple proxies, simply add them to the list
i, r = get_client_ip(request, proxy_trusted_ips=('177.2.2.2', '177.3.3.3'))
# For proxies with fixed sub-domain and dynamic IP addresses, use partial pattern
i, r = get_client_ip(request, proxy_trusted_ips=('177.2.', '177.3.'))
Note: lire avis .
la réponse D'Alexander est excellente, mais elle ne traite pas les mandataires qui renvoient parfois plusieurs adresses IP dans L'en-tête HTTP_X_FORWARDED_FOR.
la véritable adresse IP se trouve généralement à la fin de la liste, comme expliqué ici: http://en.wikipedia.org/wiki/X-Forwarded-For
la solution est une simple modification du code D'Alexandre:
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
je voudrais suggérer une amélioration à la réponse de yanchenko.
au lieu de prendre la première adresse ip dans la liste X_FORWARDED_FOR, je prends la première qui n'est pas une adresse ip interne connue, car certains routeurs ne respectent pas le protocole, et vous pouvez voir les adresses IP internes comme la première valeur de la liste.
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
j'espère que cela aidera les autres Googleurs qui ont le même problème.
la solution la plus simple (dans le cas où vous utilisez fastcgi+nignx) est ce qu'itgorilla a commenté:
Merci pour cette grande question. Mon fastcgi ne passait pas la méta-clé REMOTE_ADDR. j'ai ajouté la ligne ci-dessous dans le nginx.conf et a corrigé le problème: fastcgi_param REMOTE_ADDR $remote_addr; "151950920 – - itgorilla
Ps: j'ai ajouté cette réponse juste pour rendre sa solution plus visible.
dans mon cas aucun de ci-dessus ne fonctionne, donc je dois vérifier uwsgi
+ django
code source et passer statique param dans nginx et voir pourquoi/comment, et ci-dessous est ce que j'ai trouvé.
Env info:
version python: 2.7.5
Version Django: (1, 6, 6, 'final', 0)
nginx version: nginx/1.6.0
uwsgi: 2.0.7
Env réglage de l'info:
nginx en tant que reverse proxy écoute sur le port 80
uwsgi as upstream unix socket, va répondre à la demande éventuellement
Django config info:
USE_X_FORWARDED_HOST = True # with or without this line does not matter
NGINX config:
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";
l'obtention de toutes les params dans django app:
X-Forwarded-For : 10.10.10.10
HTTP_X_FORWARDED_FOR : 20.20.20.20
Conclusion:
donc en gros, vous devez spécifier exactement le même nom de champ/param dans nginx, et utiliser request.META[field/param]
dans l'application django.
et maintenant vous pouvez décider s'il faut ajouter un middleware (intercepteur) ou simplement analyser HTTP_X_FORWARDED_FOR
dans certaines vues.
voici une Doublure courte pour accomplir ceci:
request.META.get('HTTP_X_FORWARDED_FOR', request.META.get('REMOTE_ADDR')).split(',')[-1].strip()
j'ai aussi été proxy manquante dans la réponse ci-dessus. J'ai utilisé get_ip_address_from_request
de django_easy_timezones .
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
et voici la méthode get_ip_address_from_request
, IPv4 et IPv6 prêt:
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
la raison pour laquelle la fonctionnalité a été retirée de Django à l'origine était que l'en-tête ne peut pas en fin de Compte être fiable. La raison en est qu'il est facile d'usurper l'identité. Par exemple, la façon recommandée de configurer un proxy inverse nginx est la suivante:
add_header X-Forwarded-For $proxy_add_x_forwarded_for;
add_header X-Real-Ip $remote_addr;
quand vous faites:
curl -H 'X-Forwarded-For: 8.8.8.8, 192.168.1.2' http://192.168.1.3/
votre nginx dans myhost.com
X-Forwarded-For: 8.8.8.8, 192.168.1.2, 192.168.1.3
le X-Real-IP
sera L'adresse IP du premier mandataire précédent si vous suivez les instructions aveuglément.
dans le cas où la confiance qui vos utilisateurs sont est un problème, vous pouvez essayer quelque chose comme django-xff
: https://pypi.python.org/pypi/django-xff /
la solution la plus simple est:
from ipaddress import ip_address
et ensuite l'utiliser comme:
print(get_client_ip(request))