Kiểm soát mục tiêu proxy Nginx bằng cookie?


10

Tôi đang cố gắng chuyển đổi một proxy ngược bằng cách sử dụng một thiết lập mod_rewrite thú vị của Apache để sử dụng Nginx thay vào đó (do những lo ngại bên ngoài, chúng tôi đang chuyển từ Apache sang Nginx và hầu hết mọi thứ đều hoạt động tốt, ngoại trừ phần này).

Thiết lập ban đầu của tôi là đọc một cookie HTTP (được thiết lập bởi một số ứng dụng) và tùy thuộc vào giá trị của nó, hướng proxy ngược tới các phụ trợ khác nhau. Nó đã đi một cái gì đó như thế này:

RewriteCond %{HTTP_COOKIE}  proxy-target-A
RewriteRule ^/original-request/ http://backend-a/some-application [P,QSA]

RewriteCond %{HTTP_COOKIE}  proxy-target-B
RewriteRule ^/original-request http://backend-b/another-application [P,QSA]

RewriteRule ^/original-request http://primary-backend/original-application [P,QSA]

Tôi đang cố gắng đạt được điều tương tự bằng Nginx và cấu hình ban đầu của tôi là như thế này (trong đó "proxy_override" là tên của cookie):

location /original-request {
    if ($cookie_proxy_override = "proxy-target-A") {
        rewrite . http://backend-a/some-application;
        break;
    }
    if ($cookie_proxy_override = "proxy-target-B") {
        rewrite . http://backend-b/another-application;
        break;
    }
    proxy_pass http://primary-backend/original-application;
}

Nhưng nó đã không. Tôi đã thử xem Nginx có thể đọc cookie của tôi không bằng cách viết proxy chính để chuyển hướng đến một cái gì đó dựa trên ${cookie_proxy_override}và tôi có thể thấy rằng nó đọc nội dung tốt, nhưng ifdường như luôn thất bại.

Lần thử tiếp theo của tôi, theo câu trả lời của Rikih là:

location /original-request {
    if ($http_cookie ~ "proxy-target-A") {
        rewrite . http://backend-a/some-application;
        break;
    }
    if ($http_cookie ~ "proxy-target-B") {
        rewrite . http://backend-b/another-application;
        break;
    }
    proxy_pass http://primary-backend/original-application;
}

Và bây giờ tôi có thể thấy rằng ifkhối được kích hoạt, nhưng thay vì ủy quyền yêu cầu (như tôi nghĩ nó sẽ làm), nó trả về một chuyển hướng 302 đến URL được chỉ định - đó không phải là điều tôi đang cố gắng: Tôi cần máy chủ để chuyển tiếp yêu cầu một cách minh bạch đến các phụ trợ và chuyển phản hồi đến máy khách ban đầu.

Tôi đang làm gì sai?

Câu trả lời:


16

Tương tự như câu trả lời này . Cách tiếp cận thành ngữ của Nginx đối với loại vấn đề này là thông qua map.

Về cơ bản, bạn xác định một maptrong httpphần

map $cookie_proxy_override $my_upstream {
  default default-server-or-upstream;
  ~^(?P<name>[\w-]+) $name;
}

Sau đó, bạn chỉ cần sử dụng $my_upstreamtrong locationphần (s):

location /original-request {
  proxy_pass http://$my_upstream$uri;
}

Nginx đánh giá các biến bản đồ một cách lười biếng, chỉ một lần (mỗi yêu cầu) và khi bạn đang sử dụng chúng.


3
Cảm ơn, đó là cách tiếp cận tốt hơn sau đó là của tôi, đáng chú ý nhất là vì tôi có thể sử dụng biến cookie được đặt tên trực tiếp (không chắc tại sao tôi không thể tham gia if) và tôi đã triển khai nó. Mặc dù có một vấn đề - Nginx (ít nhất là phiên bản của tôi: 1.0.0) không thích chụp ảnh được đánh số map, vì vậy tôi phải sử dụng ~^(?P<name>[\w-]+) $name;thay thế. Tôi đã chỉnh sửa câu trả lời của bạn cho phù hợp.
Guss

3

Cuối cùng, giải pháp của tôi đạt được điều này:

server {
    ...
    set $upstream "default-server-or-upstream";
    if ($http_cookie ~ "proxy_override=([\w-]+)") {
        set $upstream $1;                                   
    }

    location /original-request {
        proxy_pass http://$upstream/original-application
    }
}

Thử nghiệm được thực hiện trong serverphạm vi cho từng yêu cầu (trước khi chuyển hướng thực tế được giải quyết) và chỉ được sử dụng để đặt biến - đây rõ ràng là cách sử dụng mô-đun "viết lại" của Nginx. Nó cũng kiểm tra toàn bộ $http_cookienhư @Rikih đã đề xuất, nhưng bao gồm tên của cookie để đảm bảo tôi không khớp với những thứ ngẫu nhiên mà mọi người có thể ném vào tôi.

Sau đó, trong locationphạm vi mà tôi muốn thực hiện chuyển hướng, tôi sử dụng tên biến chứa cấu hình ngược dòng mặc định hoặc được ghi đè bởi cookie.


0

bạn đã thử $ http_cookie chưa? http://wiki.nginx.org/HttpRewriteModule

if ($ http_cookie ~ * "proxy-target-A") {foo; }


Điều đó thực sự hiệu quả cho bài kiểm tra, mặc dù tôi không chắc tại sao tôi không thể kiểm tra tên cookie cụ thể. Điều tôi không thích là rewritenó không thực sự viết lại proxy mà thay vào đó trả về một chuyển hướng đến máy khách và tôi không thể sử dụng proxy_pass trong ifkhối. Tôi đã cập nhật câu hỏi cho phù hợp.
Guss

0

Tôi có mẫu mà tôi sử dụng để phát hiện tiêu đề yêu cầu dựa trên udid và nó đang hoạt động, có thể bạn sẽ có một số ý tưởng.

   location / {
      proxy_set_header Host $http_host;
  if ($request_uri ~ ^/(.*)udid=xxxxxxxxxxxxxx(.*)$) {
    proxy_pass   http://1.1.1.1$request_uri;
    break;
  }
  if ($request_uri ~ ^/(.*)udid=yyyyyyyyyyyyyy(.*)$) {
    proxy_pass   http://3.3.3.3$request_uri;
    break;
  }
       proxy_pass http://2.2.2.2$request_uri;
    }

Bạn đang sử dụng phiên bản nào của Nginx? Tôi đang sử dụng 1.0 và khi tôi sử dụng proxy_pass như bạn đã chỉ định ở đây, tôi nhận được thông báo lỗi này:nginx: [emerg] "proxy_pass" may not have URI part in location given by regular expression, or inside named location, or inside the "if" statement, or inside the "limit_except" block in /etc/nginx/conf.d/proxy.conf:47
Guss

tôi sử dụng nginx-0.8.53-1.el5
mô tả

có thể bạn muốn xem diễn đàn.nginx.org / read.php? 2,13955,15981
chocripple

Giải pháp trong diễn đàn là không thay đổi URI yêu cầu khi ủy quyền cho máy chủ khác, nhưng đó chính xác là những gì tôi cần làm - viết lại URI yêu cầu để nhắm mục tiêu một ứng dụng khác với URL gốc bao gồm những gì. Ngoài ra, ví dụ của bạn dường như cũng sử dụng URI yêu cầu trong proxy_passlệnh, vì vậy tôi không chắc nó có thể hoạt động như thế nào đối với bạn khi đưa ra thảo luận trên diễn đàn.
Guss
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.