كيفية الحصول على عنوان IP الحقيقي للعميل من خلال وكيل nginx/apache؟

عند استخدام nginx/apache كوكيل لـ Workerman، فإن nginx/apache يعمل فعليًا كعميل لـ Workerman، لذا فإن عنوان IP الذي يتم الحصول عليه على Workerman هو عنوان IP لخادم nginx/apache، وليس عنوان IP الفعلي للعميل. للحصول على عنوان IP الحقيقي للعميل، يمكن الرجوع إلى الطرق أدناه.

المبدأ:

تقوم nginx/apache بنقل عنوان IP الحقيقي للعميل عبر رأس HTTP، على سبيل المثال من خلال إضافة proxy_set_header X-Real-IP $remote_addr; في إعدادات الموقع في nginx. يقوم Workerman بقراءة قيمة هذا الرأس، ويقوم بتخزين هذه القيمة في $connection对象里، (يمكن لـ GatewayWorker تخزينها في المتغير $_SESSION)، وعند الاستخدام يمكن قراءة المتغير مباشرة.

ملاحظة:

تنطبق الإعدادات التالية على بروتوكولات http/https وws/wss. بالنسبة لبروتوكولات أخرى، يكون طريقة الحصول على عنوان IP للعميل مشابهة، ويجب على خادم الوكيل إدراج جزء من بيانات IP في حزمة البيانات لتمرير عنوان IP الحقيقي للعميل.

إعداد nginx كما يلي:

server {
  listen 443;

  ssl on;
  ssl_certificate /etc/ssl/server.pem;
  ssl_certificate_key /etc/ssl/server.key;
  ssl_session_timeout 5m;
  ssl_session_cache shared:SSL:50m;
  ssl_protocols SSLv3 SSLv2 TLSv1 TLSv1.1 TLSv1.2;
  ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;

  location /wss
  {
    proxy_pass http://127.0.0.1:8282;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    # هذه الجزء يستخدم رأس http لتمرير عنوان IP الحقيقي للعميل
    proxy_set_header X-Real-IP $remote_addr;
  }

  # location / {} إعدادات أخرى للموقع...
}

يقرأ Workerman عنوان IP للعميل من الرأس المهيأ في nginx

<?php

use Workerman\Worker;
use Workerman\Connection\TcpConnection;
require_once __DIR__ . '/vendor/autoload.php';

$worker = new Worker('websocket://0.0.0.0:7272');

/**
 * رد الاتصال عند مصافحة العميل عبر websocket
 * في رد الاتصال onWebSocketConnect يتم الحصول على قيمة X_REAL_IP الممررة عبر http من nginx
 */
$worker->onWebSocketConnect = function(TcpConnection $connection, $request){
    /**
     * الكائن connection ليس لديه خاصية realIP، هنا نقوم بإضافة خاصية realIP للكائن connection ديناميكيًا
     * تذكر أن كائنات php يمكن إضافة خصائص ديناميكيًا، يمكنك أيضًا استخدام اسم الخاصية الذي تفضله
     */
    //$connection->realIP = $_SERVER['HTTP_X_REAL_IP']; // استخدام Workerman v4
    $connection->realIP = $request->header('x-real-ip'); // استخدام Workerman v5
};
$worker->onMessage = function(TcpConnection $connection, $data)
{
    // عند استخدام عنوان IP الحقيقي للعميل، يمكن استخدام $connection->realIP مباشرة
    $connection->send($connection->realIP);
};
Worker::runAll();

GatewayWorker يحصل على عنوان IP للعميل من الرأس المهيأ في nginx

أضف الكود أدناه إلى Events.php

class Events
{
   public static function onWebsocketConnect($client_id, $data)
   {    
        $_SESSION['realIP'] = $data['server']['HTTP_X_REAL_IP'];
   }
   // .... كود آخر تم حذفه....
}

بعد إضافة الكود، يحتاج إلى إعادة تشغيل GatewayWorker.

بهذه الطريقة، يمكنك استخدام $_SESSION['realIP'] للحصول على عنوان IP الحقيقي للعميل في طرق onMessage وonClose في Events.php.

ملاحظة: لا يمكن استخدام $_SESSION['realIP'] بشكل مباشر في onWorkerStart وonConnect وonWorkerStop في Events.php.