Làm thế nào để lấy địa chỉ IP thật của khách hàng thông qua proxy nginx/apache?
Khi sử dụng nginx/apache làm proxy cho workerman, nginx/apache thực sự hoạt động như một khách hàng của workerman, vì vậy địa chỉ IP nhận được trên workerman là địa chỉ IP của máy chủ nginx/apache chứ không phải địa chỉ IP thực tế của khách hàng. Để lấy địa chỉ IP thật của khách hàng, bạn có thể tham khảo các phương pháp dưới đây.
Nguyên lý:
nginx/apache truyền địa chỉ IP thật của khách hàng qua http header, ví dụ, trong cấu hình nginx, trong location thêm proxy_set_header X-Real-IP $remote_addr; để thiết lập. workerman đọc giá trị header này và lưu giá trị vào $connection (GatewayWorker có thể lưu vào biến $_SESSION), khi sử dụng thì chỉ cần đọc biến này.
Lưu ý:
Cấu hình dưới đây phù hợp cho giao thức http/https ws/wss. Các giao thức khác để lấy địa chỉ IP của khách hàng có cách tương tự, cần có máy chủ proxy chèn một đoạn dữ liệu IP vào gói tin để truyền lại địa chỉ IP thật của khách hàng.
Cấu hình nginx tương tự như sau:
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";
# Phần này sử dụng http header để truyền lại địa chỉ IP thật của khách hàng
proxy_set_header X-Real-IP $remote_addr;
}
# location / {} Cấu hình khác của trang web...
}
Workerman đọc địa chỉ IP khách hàng từ header đã thiết lập của nginx
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('websocket://0.0.0.0:7272');
/**
* Callback onWebSocketConnect khi khách hàng websocket bắt tay
* Trong callback onWebSocketConnect để lấy giá trị X_REAL_IP từ http header mà nginx truyền vào
*/
$worker->onWebSocketConnect = function(TcpConnection $connection, $request){
/**
* Đối tượng connection vốn không có thuộc tính realIP, ở đây thêm thuộc tính realIP cho đối tượng connection
* Nhớ rằng đối tượng php có thể bổ sung thuộc tính một cách động, bạn cũng có thể sử dụng tên thuộc tính mà bạn thích
*/
//$connection->realIP = $_SERVER['HTTP_X_REAL_IP']; // Cách sử dụng workerman v4
$connection->realIP = $request->header('x-real-ip'); // Cách sử dụng workerman v5
};
$worker->onMessage = function(TcpConnection $connection, $data)
{
// Khi sử dụng địa chỉ IP thật của khách hàng, chỉ cần sử dụng $connection->realIP
$connection->send($connection->realIP);
};
Worker::runAll();
GatewayWorker lấy địa chỉ IP khách hàng từ header đã thiết lập của nginx
Thêm đoạn mã dưới đây vào Events.php
class Events
{
public static function onWebsocketConnect($client_id, $data)
{
$_SESSION['realIP'] = $data['server']['HTTP_X_REAL_IP'];
}
// .... Bỏ qua mã khác....
}
Sau khi thêm mã, bạn cần khởi động lại GatewayWorker.
Như vậy, bạn có thể lấy địa chỉ IP thật của khách hàng qua $_SESSION['realIP'] trong các phương thức onMessage và onClose trong Events.php.
Lưu ý: Các phương thức
onWorkerStart,onConnect,onWorkerStoptrong Events.php không thể trực tiếp sử dụng$_SESSION['realIP'].