web-dev-qa-db-fra.com

Comment obtenir l'adresse IP de l'utilisateur dans Django?

Comment obtenir l'adresse IP de l'utilisateur dans Django?

J'ai une vue comme ça:

# 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
260
avatar
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 le proxy inverse (le cas échéant) est correctement configuré (par exemple, mod_rpaf installé pour Apache).

Remarque: ce qui précède utilise le premier élément dans X-Forwarded-For, mais vous pouvez utiliser le dernier élément (par exemple, dans le cas de Heroku: Obtenir la véritable adresse IP du client sur Herok )

Et ensuite, passez simplement la requête en argument;

get_client_ip(request)
383
yanchenko

Vous pouvez utiliser Django-ipware qui supporte Python 2 & 3 et gère IPv4 & IPv6 .

Installer:

pip installer Django-ipware

Utilisation 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)

Utilisation avancée:

En-tête personnalisé - En-tête de demande 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'])

Nombre de mandataires - Django le serveur est derrière un nombre fixe de mandataires

i, r = get_client_ip(request, proxy_count=1)

Trusted Proxies - Django le serveur est derrière un ou plusieurs proxy connus et approuvés

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.'))

Remarque: lisez ceci remarque .

193
un33k

La réponse d'Alexander est excellente, mais le traitement des proxys qui renvoient parfois plusieurs adresses IP dans l'en-tête HTTP_X_FORWARDED_FOR manque.

La vraie adresse IP est 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'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
75
Sævar

Je voudrais suggérer une amélioration à la réponse de Yanchenko.

Au lieu de prendre la première adresse IP de la liste X_FORWARDED_FOR, je prends la première adresse IP interne inconnue, 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 aide les autres Googlers qui ont le même problème.

9
Doody P

voici une courte ligne pour accomplir ceci:

request.META.get('HTTP_X_FORWARDED_FOR', request.META.get('REMOTE_ADDR', '')).split(',')[0].strip()
7
masterbase

La solution la plus simple (au cas où vous utilisez fastcgi + nignx) est ce que itgorilla a commenté:

Merci pour cette excellente question. Mon fastcgi ne passait pas la clé méta REMOTE_ADDR. J'ai ajouté la ligne ci-dessous dans le fichier nginx.conf et résolu le problème: fastcgi_param REMOTE_ADDR $ remote_addr; - itgorilla

Ps: J'ai ajouté cette réponse juste pour rendre sa solution plus visible.

6
Juande Carrion

Dans mon cas, aucun des projets ci-dessus ne fonctionne, je dois donc vérifier le code source uwsgi + Django, passer le paramètre statique dans nginx et voir pourquoi/comment.

Env info:
version python: 2.7.5
Version Django: (1, 6, 6, 'final', 0)
nginx version: nginx/1.6.0
uwsgi: 2.0.7

Informations de réglage Env:
nginx en tant que proxy inverse en écoute sur le port 80 uwsgi en tant que socket unix en amont, répondra éventuellement à la demande

info de configuration Django:

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";

obtenir tous les paramètres dans Django app:

X-Forwarded-For :       10.10.10.10
HTTP_X_FORWARDED_FOR :  20.20.20.20

Conclusion:

Donc, fondamentalement, vous devez spécifier exactement le même nom de champ/paramètre dans nginx et utiliser request.META[field/param] dans Django app.

Et maintenant, vous pouvez décider d’ajouter un middleware (intercepteur) ou simplement d’analyser HTTP_X_FORWARDED_FOR dans certaines vues.

5
xxmajia

Il me manquait également proxy 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 ready:

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
Lucas03

La raison pour laquelle la fonctionnalité a été supprimée de Django à l'origine est que l'en-tête ne peut finalement pas être approuvé. La raison en est qu'il est facile de se faire passer. Par exemple, la méthode recommandée pour configurer un proxy inverse nginx consiste à:

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

Quand tu fais:

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

Votre nginx sur myhost.com enverra:

X-Forwarded-For: 8.8.8.8, 192.168.1.2, 192.168.1.3

Le X-Real-IP sera l'IP du premier proxy précédent si vous suivez les instructions à l'aveuglette.

Si vous ne voulez pas savoir qui sont vos utilisateurs, vous pouvez essayer quelque chose comme: Django-xff: https://pypi.python.org/pypi/Django-xff/

2
ferrix

Dans Django.VERSION (2, 1, 1, 'final', 0) gestionnaire de demandes

sock=request._stream.stream.raw._sock
#<socket.socket fd=1236, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.1.111', 8000), raddr=('192.168.1.111', 64725)>
client_ip,port=sock.getpeername()

si vous appelez le code ci-dessus deux fois, vous pouvez avoir

AttributeError (l'objet "'_ io.BytesIO' n'a pas d'attribut 'stream'",)

AttributeError (l'objet "LimitedStream" n'a pas d'attribut "raw" ")

0
CS QGB