รับที่อยู่ IP ของผู้เยี่ยมชมโดยใช้ Flask สำหรับ Python


220

ฉันสร้างเว็บไซต์ที่ผู้ใช้สามารถเข้าสู่ระบบและดาวน์โหลดไฟล์โดยใช้Flask micro-framework (จากWerkzeug ) ซึ่งใช้ Python (2.6 ในกรณีของฉัน)

ฉันต้องได้รับที่อยู่ IP ของผู้ใช้เมื่อพวกเขาเข้าสู่ระบบ (เพื่อการเข้าสู่ระบบ) ไม่มีใครรู้วิธีการทำเช่นนี้? แน่นอนมีวิธีที่จะทำกับ Python หรือไม่?

คำตอบ:


295

โปรดดูเอกสารเกี่ยวกับวิธีการเข้าถึงขอวัตถุremote_addrและจากนั้นได้รับจากนี้ขอวัตถุเดียวกันแอตทริบิวต์

ตัวอย่างรหัส

from flask import request
from flask import jsonify

@app.route("/get_my_ip", methods=["GET"])
def get_my_ip():
    return jsonify({'ip': request.remote_addr}), 200

สำหรับข้อมูลเพิ่มเติมโปรดดูที่เอกสาร Werkzeug


1
บางครั้งมันอาจมีประโยชน์: request.access_route [0]
Jonathan Prates

46
สำหรับ nginx นั้นจะส่งที่อยู่ IP จริงภายใต้HTTP_X_FORWARDED_FORดังนั้นให้แน่ใจว่าคุณไม่ได้ลงท้ายด้วย localhost สำหรับแต่ละคำขอ
Rasty Turek

95

พร็อกซี่สามารถทำให้เรื่องยุ่งยากเล็กน้อยตรวจสอบให้แน่ใจว่าได้ตรวจสอบProxyFix ( Flask docs ) หากคุณใช้งานอยู่ ดูrequest.environในสภาพแวดล้อมเฉพาะของคุณ ด้วย nginx บางครั้งฉันจะทำสิ่งนี้:

from flask import request   
request.environ.get('HTTP_X_REAL_IP', request.remote_addr)   

เมื่อพร็อกซีเช่น nginx ส่งต่อที่อยู่พวกเขามักจะรวม IP ดั้งเดิมอยู่ที่ไหนสักแห่งในส่วนหัวของคำขอ

ปรับปรุง ดูการดำเนินการรักษาความปลอดภัยขวด ตรวจสอบเอกสารเกี่ยวกับ ProxyFix อีกครั้งก่อนนำไปใช้ โซลูชันของคุณอาจแตกต่างกันไปตามสภาพแวดล้อมเฉพาะของคุณ


2
สิ่งนี้จะทำงานเมื่อคุณตั้งค่าฟิลด์ที่เหมาะสมในการกำหนดค่าพร็อกซีย้อนกลับของคุณ ใช้ในการผลิต
drahnr

3
@drahnr ใช่แน่นอน โค้ดด้านบนใช้งานได้ถ้าอยู่ใน nginx เช่นคุณตั้งค่า: proxy_set_header X-Real-IP $ remote_addr;
pors

@pors - มันใช้งานได้ ฉันมีการตั้งค่าเดียวกันใน nginx ของฉัน conf คุณ แต่ฉันก็ยังไม่เข้าใจว่าทำไมรหัส: request.headers.get ('X-Real-IP', request.remote_addr) ไม่ทำงาน หมายเหตุโดยสังหรณ์ใจฉันจะได้รับค่าจากส่วนหัวและใช้ชื่อ 'X-Real-IP' ซึ่งเป็นวิธีที่ nginx conf ของฉันเป็น
lostdorje

82

ที่จริงแล้วสิ่งที่คุณจะพบคือเมื่อได้รับสิ่งต่อไปนี้จะทำให้คุณได้รับที่อยู่ของเซิร์ฟเวอร์:

request.remote_addr

หากคุณต้องการที่อยู่ IP ของลูกค้าให้ใช้สิ่งต่อไปนี้:

request.environ['REMOTE_ADDR']

4
เฉพาะในกรณีที่คุณอยู่หลังพร็อกซีย้อนกลับเท่านั้น
Ry-

3
@minitech ฉันจะบอกว่ารหัสของคุณไม่ควรสนใจว่าคุณอยู่หลัง proxy หรือไม่ หากตัวเลือกนี้ใช้งานได้อย่างน่าเชื่อถือโดยไม่คำนึงถึง reverse proxy และอีกอันถือว่าคุณไม่ได้อยู่เบื้องหลัง reverse proxy ควรเลือกตัวเลือกนี้ (ฉันจะทดสอบสิ่งนี้หากฉันสามารถตั้งค่าพร็อกซีย้อนกลับได้ง่าย แต่จะใช้เวลามากกว่าที่ฉันมีอยู่ในขณะนี้)
jpmc26

@ jpmc26: ฉันไม่เห็นเหตุผลว่าทำไมมันควรจะทำงานได้เลย request.remote_addrดูเหมือนว่าคุณสมบัติที่ควรได้รับที่อยู่ระยะไกลขึ้นอยู่กับว่า reverse proxy เชื่อถือได้หรือไม่
Ry-

3
ใช้ mod_wsgi, request.remote_addr ส่งคืนที่อยู่เซิร์ฟเวอร์ทุกครั้ง request.environ ['REMOTE_ADDR'] ทำให้ฉันมีที่อยู่ IP สาธารณะของลูกค้า บางทีฉันอาจจะหายไปบางอย่าง
Chiedo

@ jpmc26 คุณบ่อยทำจำเป็นที่จะต้องดูแลถ้าคุณอยู่เบื้องหลังพร็อกซี่ที่ห่างไกล หากคุณเป็นเช่นนั้น IP ที่เชื่อมต่อกับคุณจะเป็นของพร็อกซีเซิร์ฟเวอร์ระยะไกลและคุณจะต้องพึ่งพาส่วนหัวที่เพิ่มเพื่อรับ IP ไคลเอ็นต์ดั้งเดิม หากคุณไม่ได้ส่วนหัวเหล่านั้นมักจะไม่ปรากฏและคุณต้องการใช้ IP การเชื่อมต่อเป็น IP ลูกค้า และคุณไม่สามารถตรวจสอบส่วนหัวและถอยกลับไปยังการเชื่อมต่อ IP ได้หากไม่ได้อยู่เพราะถ้าคุณไม่ได้อยู่หลังพร็อกซีย้อนกลับลูกค้าสามารถหลอกลวง IP ของพวกเขาได้ซึ่งในหลาย ๆ สถานการณ์จะเป็นปัญหาด้านความปลอดภัย .
Mark Amery

28

ที่อยู่ IP ของผู้ใช้สามารถดึงข้อมูลได้โดยใช้ตัวอย่างต่อไปนี้:

from flask import request
print(request.remote_addr)

3
นี้ไม่เป็นความจริงถ้า app ทำงานอยู่เบื้องหลังพร็อกซีเซิร์ฟเวอร์เช่นNginx ซึ่งมันมักจะอยู่ในการผลิต
datashaman

17

ฉันมีNginxและต่ำกว่ากำหนดค่าNginx :

server {
    listen 80;
    server_name xxxxxx;
    location / {
               proxy_set_header   Host                 $host;
               proxy_set_header   X-Real-IP            $remote_addr;
               proxy_set_header   X-Forwarded-For      $proxy_add_x_forwarded_for;
               proxy_set_header   X-Forwarded-Proto    $scheme;

               proxy_pass http://x.x.x.x:8000;
        }
}

@โซลูชันtirtha-r ใช้งานได้สำหรับฉัน

#!flask/bin/python
from flask import Flask, jsonify, request
app = Flask(__name__)

@app.route('/', methods=['GET'])
def get_tasks():
    if request.environ.get('HTTP_X_FORWARDED_FOR') is None:
        return jsonify({'ip': request.environ['REMOTE_ADDR']}), 200
    else:
        return jsonify({'ip': request.environ['HTTP_X_FORWARDED_FOR']}), 200

if __name__ == '__main__':
    app.run(debug=True,host='0.0.0.0', port=8000)

คำขอและคำตอบของฉัน:

curl -X GET http://test.api

{
    "ip": "Client Ip......"
}

13

รหัสด้านล่างจะให้ IP สาธารณะของลูกค้าเสมอ (ไม่ใช่ IP ส่วนตัวที่อยู่หลังพร็อกซี)

from flask import request

if request.environ.get('HTTP_X_FORWARDED_FOR') is None:
    print(request.environ['REMOTE_ADDR'])
else:
    print(request.environ['HTTP_X_FORWARDED_FOR']) # if behind a proxy

คำตอบนี้พร้อมกับการเปลี่ยนการตั้งค่า nginx ตามบล็อกนี้เหมาะสำหรับฉัน calvin.me/forward-ip-addresses-when-using-nginx-proxy
Romano Vacca


3

ถ้าคุณใช้ Nginx ที่อยู่เบื้องหลังตัวสร้างสมดุลอื่น ๆ เช่น AWS Application Balancer, HTTP_X_FORWARDED_FOR จะส่งกลับรายการที่อยู่ สามารถแก้ไขได้เช่นนั้น:

if 'X-Forwarded-For' in request.headers:
    proxy_data = request.headers['X-Forwarded-For']
    ip_list = proxy_data.split(',')
    user_ip = ip_list[0]  # first address in list is User IP
else:
    user_ip = request.remote_addr  # For local development

1

หากคุณใช้สภาพแวดล้อม Gunicorn และ Nginx เทมเพลตรหัสต่อไปนี้จะทำงานให้คุณ

addr_ip4 = request.remote_addr

0

สิ่งนี้ควรทำงาน มันให้ที่อยู่ IP ของลูกค้า (โฮสต์ระยะไกล)

โปรดทราบว่ารหัสนี้ทำงานบนฝั่งเซิร์ฟเวอร์

from mod_python import apache

req.get_remote_host(apache.REMOTE_NOLOOKUP)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.