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
231
demandé sur avatar 2011-01-03 05:55:05

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)
344
répondu yanchenko 2017-05-23 10:31:17

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 .

181
répondu un33k 2018-04-18 21:01:03

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
69
répondu Sævar 2011-05-12 09:38:47

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.

9
répondu Doody P 2013-07-28 17:54:51

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.

6
répondu Juande Carrion 2011-09-20 06:48:18

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.

4
répondu xxmajia 2017-03-07 02:20:17

voici une Doublure courte pour accomplir ceci:

request.META.get('HTTP_X_FORWARDED_FOR', request.META.get('REMOTE_ADDR')).split(',')[-1].strip()
4
répondu masterbase 2017-09-16 18:16:03

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
2
répondu Lucas03 2016-01-31 00:22:42

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 /

1
répondu ferrix 2016-01-12 12:50:48

la solution la plus simple est:

from ipaddress import ip_address

et ensuite l'utiliser comme:

print(get_client_ip(request))
-10
répondu Rahul Sharma 2016-08-04 06:38:57