直接アクセスのみ
クライアントが Django に直接アクセスすると決まっている場合は、HTTP ヘッダの'REMOTE_ADDR'
を参照するだけで IP アドレスを取得することができます。
from django.http import HttpResponse
from django.views import View
class MyView(View):
def get(self, request):
# request オブジェクトから'REMOTE_ADDR'ヘッダを取得する。
client_addr = request.META.get('REMOTE_ADDR')
# 動作確認のため、取得したアドレスをそのまま返す。
return HttpResponse(client_addr)
リバースプロキシ対応
しかし上記の方法では、クライアントと Django の間に Nginx などのリバースプロキシがある場合は、'REMOTE_ADDR'
で取得できる IP アドレスがリバースプロキシのアドレスになってしまいます(例: Nginx が同じホストにあると127.0.0.1
になる)。
途中で1回以上転送された場合は、同じく HTTP ヘッダの'HTTP_X_FORWARDED_FOR'
を参照すれば転送経路の IP アドレスがカンマ区切り文字列で取得できるので、この先頭要素からクライアントの IP アドレスを取得することができます。
また'HTTP_X_FORWARDED_FOR'
ヘッダがない場合は直接アクセスなので、上記と同様に'REMOTE_ADDR'
で取得します。
from django.http import HttpResponse
from django.views import View
class MyView(View):
def get(self, request):
# 'HTTP_X_FORWARDED_FOR'ヘッダを参照して転送経路のIPアドレスを取得する。
forwarded_addresses = request.META.get('HTTP_X_FORWARDED_FOR')
if forwarded_addresses:
# 'HTTP_X_FORWARDED_FOR'ヘッダがある場合: 転送経路の先頭要素を取得する。
client_addr = forwarded_addresses.split(',')[0]
else:
# 'HTTP_X_FORWARDED_FOR'ヘッダがない場合: 直接接続なので'REMOTE_ADDR'ヘッダを参照する。
client_addr = request.META.get('REMOTE_ADDR')
# 動作確認のため、取得したアドレスをそのまま返す。
return HttpResponse(client_addr)
ipwareを使う
django-ipware を pip でインストールします。
pip3 install django-ipware
インポートしてget_client_ip
関数を使えば、たった 1行でクライアントのアドレスを取得でき、もちろんリバースプロキシに対応しています。
from django.http import HttpResponse
from django.views import View
from ipware import get_client_ip
class MyView(View):
def get(self, request):
client_addr, _ = get_client_ip(request)
return HttpResponse(client_addr)
参照する HTTP ヘッダは'HTTP_X_FORWARDED_FOR'
と'REMOTE_ADDR'
だけでなく、デフォルトで以下の優先順位でクライアントのアドレスを取得します。
# The default meta precedence order
IPWARE_META_PRECEDENCE_ORDER = (
'HTTP_X_FORWARDED_FOR', 'X_FORWARDED_FOR', # <client>, <proxy1>, <proxy2>
'HTTP_CLIENT_IP',
'HTTP_X_REAL_IP',
'HTTP_X_FORWARDED',
'HTTP_X_CLUSTER_CLIENT_IP',
'HTTP_FORWARDED_FOR',
'HTTP_FORWARDED',
'HTTP_VIA',
'REMOTE_ADDR',
)
さらにget_client_ip
関数を呼び出す時に、指定した優先順位でデフォルトの優先順位をオーバーライドすることもできます。
client_addr, is_routable = get_client_ip(request, request_header_order=['X_FORWARDED_FOR', 'REMOTE_ADDR'])
参考リンク
Stack Overflow "How do I get user IP address in django?"
https://stackoverflow.com/questions/4581789/how-do-i-get-user-ip-address-in-django
GitHub - un33k/django-ipware "A Django application to retrieve client's IP address"
https://github.com/un33k/django-ipware