如何获得django中的用户IP地址?

时间:2021-11-03 20:24:22

How do I get user's IP in django?

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

I have a view like this:

我有这样的观点:

# 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())

But I get this error:

但是我得到了这个错误:

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

11 个解决方案

#1


321  

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

Make sure you have reverse proxy (if any) configured correctly (e.g. mod_rpaf installed for Apache).

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

Note: the above uses the first item in X-Forwarded-For, but you might want to use the last item (e.g., in the case of Heroku: Get client's real IP address on Heroku)

注意:上面使用了x -转发中的第一项,但是您可能想要使用最后一项(例如,在Heroku的例子中:获取客户端在Heroku上的真实IP地址)。

And then just pass the request as argument to it;

然后将请求作为参数传递给它;

get_client_ip(request)

#2


168  

You can use django-ipware which supports Python 2 & 3 and handles IPv4 & IPv6.

您可以使用支持Python 2 & 3的django-ipware并处理IPv4和IPv6。

Install:

安装:

pip install django-ipware

pip安装django-ipware

Simple Usage:

简单的用法:

To get client's IP address.

获取客户端IP地址。

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

Advanced Usage:

先进的用法:

Custom Header - Custom request header for ipware to look at

自定义标头——ipware的自定义请求标头。

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

Proxy Count - Django server is behind a fixed number of proxies

代理计数- Django服务器是一个固定数量的代理。

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

Trusted Proxies - Django server is behind one or more known & trusted proxies

受信任的代理——Django服务器位于一个或多个已知和可信代理的后面。

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: read this notice.

注意:阅读此通知。

#3


68  

Alexander's answer is great, but lacks the handling of proxies that sometimes return multiple IP's in the HTTP_X_FORWARDED_FOR header.

亚历山大的回答很好,但是缺少对代理的处理,这些代理有时会在HTTP_X_FORWARDED_FOR头中返回多个IP。

The real IP is usually at the end of the list, as explained here: http://en.wikipedia.org/wiki/X-Forwarded-For

真正的IP通常在列表的末尾,如这里所解释的:http://en.wikipedia.org/wiki/x - - for。

The solution is a simple modification of Alexander's code:

解决方案是简单修改亚历山大的代码:

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

#4


9  

I would like to suggest an improvement to yanchenko's answer.

我想建议改进一下yanchenko的答案。

Instead of taking the first ip in the X_FORWARDED_FOR list, I take the first one which in not a known internal ip, as some routers don't respect the protocol, and you can see internal ips as the first value of the list.

我没有使用X_FORWARDED_FOR列表中的第一个ip,而是选择了第一个不知道内部ip的ip,因为一些路由器不遵守协议,并且您可以将内部ip视为列表的第一个值。

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

I hope this helps fellow Googlers who have the same problem.

我希望这能帮助那些有同样问题的谷歌员工。

#5


6  

The simpliest solution (in case you are using fastcgi+nignx) is what itgorilla commented:

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

Thank you for this great question. My fastcgi was not passing the REMOTE_ADDR meta key. I added the line below in the nginx.conf and fixed the problem: fastcgi_param REMOTE_ADDR $remote_addr; – itgorilla

谢谢你提的这个问题。我的fastcgi并没有传递REMOTE_ADDR meta密钥。我在nginx中添加了这条线。conf并解决了问题:fastcgi_param REMOTE_ADDR $ REMOTE_ADDR;——itgorilla

Ps: I added this answer just to make his solution more visible.

我添加了这个答案,只是为了让他的解决方案更加清晰可见。

#6


4  

In my case none of above works, so I have to check uwsgi + django source code and pass static param in nginx and see why/how, and below is what I have found.

在我的例子中,上面没有任何工作,所以我必须检查uwsgi + django源代码并在nginx中传递静态param,并查看为什么/如何,下面是我所找到的。

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

Env信息:python版本:2.7.5 Django版本:(1、6、6、“final”、0)nginx版本:nginx/1.6.0 uwsgi: 2.0.7。

Env setting info:
nginx as reverse proxy listening at port 80 uwsgi as upstream unix socket, will response to the request eventually

Env设置信息:nginx作为反向代理监听在端口80 uwsgi作为上行unix套接字,将最终响应请求。

Django config info:

Django配置信息:

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

nginx config:

nginx配置:

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

getting all the params in django app:

在django应用程序中获取所有参数:

X-Forwarded-For :       10.10.10.10
HTTP_X_FORWARDED_FOR :  20.20.20.20

Conclusion:

结论:

So basically, you have to specify exactly the same field/param name in nginx, and use request.META[field/param] in django app.

因此,基本上,您必须在nginx中指定完全相同的字段/param名称,并使用请求。元(字段/ param)在django应用程序。

And now you can decide whether to add a middleware (interceptor) or just parse HTTP_X_FORWARDED_FOR in certain views.

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

#7


2  

I was also missing proxy in above answer. I used get_ip_address_from_request from django_easy_timezones.

我在上面的回答中也缺少了代理。我使用了来自django_easy_timezone的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

And here is method get_ip_address_from_request, IPv4 and IPv6 ready:

这里是方法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

#8


2  

here is a short one liner to accomplish this:

以下是完成这一任务的简短的一句话:

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

#9


1  

The reason the functionality was removed from Django originally was that the header cannot ultimately be trusted. The reason is that it is easy to spoof. For example the recommended way to configure an nginx reverse proxy is to:

从Django中删除功能的原因是,最终不能信任header。原因是它很容易被欺骗。例如,建议配置nginx反向代理的方法是:

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

When you do:

当你做的事:

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

Your nginx in myhost.com will send onwards:

您的nginx在myhost.com将发送:

X-Forwarded-For: 8.8.8.8, 192.168.1.2, 192.168.1.3

The X-Real-IP will be the IP of the first previous proxy if you follow the instructions blindly.

如果你盲目地遵从指令,X-Real-IP将是第一个代理的IP。

In case trusting who your users are is an issue, you could try something like django-xff: https://pypi.python.org/pypi/django-xff/

如果信任您的用户是一个问题,您可以尝试类似django-xff: https://pypi.python.org/pypi/django-xff/。

#10


0  

request.META.get('REMOTE_ADDR') would be good enough here.

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

#11


-8  

The most easy solution to this is:

最简单的解决办法是:

from ipaddress import ip_address

and then use it like:

然后使用它:

print(get_client_ip(request))

#1


321  

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

Make sure you have reverse proxy (if any) configured correctly (e.g. mod_rpaf installed for Apache).

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

Note: the above uses the first item in X-Forwarded-For, but you might want to use the last item (e.g., in the case of Heroku: Get client's real IP address on Heroku)

注意:上面使用了x -转发中的第一项,但是您可能想要使用最后一项(例如,在Heroku的例子中:获取客户端在Heroku上的真实IP地址)。

And then just pass the request as argument to it;

然后将请求作为参数传递给它;

get_client_ip(request)

#2


168  

You can use django-ipware which supports Python 2 & 3 and handles IPv4 & IPv6.

您可以使用支持Python 2 & 3的django-ipware并处理IPv4和IPv6。

Install:

安装:

pip install django-ipware

pip安装django-ipware

Simple Usage:

简单的用法:

To get client's IP address.

获取客户端IP地址。

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

Advanced Usage:

先进的用法:

Custom Header - Custom request header for ipware to look at

自定义标头——ipware的自定义请求标头。

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

Proxy Count - Django server is behind a fixed number of proxies

代理计数- Django服务器是一个固定数量的代理。

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

Trusted Proxies - Django server is behind one or more known & trusted proxies

受信任的代理——Django服务器位于一个或多个已知和可信代理的后面。

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: read this notice.

注意:阅读此通知。

#3


68  

Alexander's answer is great, but lacks the handling of proxies that sometimes return multiple IP's in the HTTP_X_FORWARDED_FOR header.

亚历山大的回答很好,但是缺少对代理的处理,这些代理有时会在HTTP_X_FORWARDED_FOR头中返回多个IP。

The real IP is usually at the end of the list, as explained here: http://en.wikipedia.org/wiki/X-Forwarded-For

真正的IP通常在列表的末尾,如这里所解释的:http://en.wikipedia.org/wiki/x - - for。

The solution is a simple modification of Alexander's code:

解决方案是简单修改亚历山大的代码:

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

#4


9  

I would like to suggest an improvement to yanchenko's answer.

我想建议改进一下yanchenko的答案。

Instead of taking the first ip in the X_FORWARDED_FOR list, I take the first one which in not a known internal ip, as some routers don't respect the protocol, and you can see internal ips as the first value of the list.

我没有使用X_FORWARDED_FOR列表中的第一个ip,而是选择了第一个不知道内部ip的ip,因为一些路由器不遵守协议,并且您可以将内部ip视为列表的第一个值。

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

I hope this helps fellow Googlers who have the same problem.

我希望这能帮助那些有同样问题的谷歌员工。

#5


6  

The simpliest solution (in case you are using fastcgi+nignx) is what itgorilla commented:

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

Thank you for this great question. My fastcgi was not passing the REMOTE_ADDR meta key. I added the line below in the nginx.conf and fixed the problem: fastcgi_param REMOTE_ADDR $remote_addr; – itgorilla

谢谢你提的这个问题。我的fastcgi并没有传递REMOTE_ADDR meta密钥。我在nginx中添加了这条线。conf并解决了问题:fastcgi_param REMOTE_ADDR $ REMOTE_ADDR;——itgorilla

Ps: I added this answer just to make his solution more visible.

我添加了这个答案,只是为了让他的解决方案更加清晰可见。

#6


4  

In my case none of above works, so I have to check uwsgi + django source code and pass static param in nginx and see why/how, and below is what I have found.

在我的例子中,上面没有任何工作,所以我必须检查uwsgi + django源代码并在nginx中传递静态param,并查看为什么/如何,下面是我所找到的。

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

Env信息:python版本:2.7.5 Django版本:(1、6、6、“final”、0)nginx版本:nginx/1.6.0 uwsgi: 2.0.7。

Env setting info:
nginx as reverse proxy listening at port 80 uwsgi as upstream unix socket, will response to the request eventually

Env设置信息:nginx作为反向代理监听在端口80 uwsgi作为上行unix套接字,将最终响应请求。

Django config info:

Django配置信息:

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

nginx config:

nginx配置:

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

getting all the params in django app:

在django应用程序中获取所有参数:

X-Forwarded-For :       10.10.10.10
HTTP_X_FORWARDED_FOR :  20.20.20.20

Conclusion:

结论:

So basically, you have to specify exactly the same field/param name in nginx, and use request.META[field/param] in django app.

因此,基本上,您必须在nginx中指定完全相同的字段/param名称,并使用请求。元(字段/ param)在django应用程序。

And now you can decide whether to add a middleware (interceptor) or just parse HTTP_X_FORWARDED_FOR in certain views.

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

#7


2  

I was also missing proxy in above answer. I used get_ip_address_from_request from django_easy_timezones.

我在上面的回答中也缺少了代理。我使用了来自django_easy_timezone的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

And here is method get_ip_address_from_request, IPv4 and IPv6 ready:

这里是方法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

#8


2  

here is a short one liner to accomplish this:

以下是完成这一任务的简短的一句话:

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

#9


1  

The reason the functionality was removed from Django originally was that the header cannot ultimately be trusted. The reason is that it is easy to spoof. For example the recommended way to configure an nginx reverse proxy is to:

从Django中删除功能的原因是,最终不能信任header。原因是它很容易被欺骗。例如,建议配置nginx反向代理的方法是:

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

When you do:

当你做的事:

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

Your nginx in myhost.com will send onwards:

您的nginx在myhost.com将发送:

X-Forwarded-For: 8.8.8.8, 192.168.1.2, 192.168.1.3

The X-Real-IP will be the IP of the first previous proxy if you follow the instructions blindly.

如果你盲目地遵从指令,X-Real-IP将是第一个代理的IP。

In case trusting who your users are is an issue, you could try something like django-xff: https://pypi.python.org/pypi/django-xff/

如果信任您的用户是一个问题,您可以尝试类似django-xff: https://pypi.python.org/pypi/django-xff/。

#10


0  

request.META.get('REMOTE_ADDR') would be good enough here.

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

#11


-8  

The most easy solution to this is:

最简单的解决办法是:

from ipaddress import ip_address

and then use it like:

然后使用它:

print(get_client_ip(request))