सभी उपयोगकर्ताओं के लिए प्रमाणित अनुरोध कैशिंग


9

मैं एक वेब ऐप पर काम कर रहा हूं, जिसमें समान सामग्री का अनुरोध करने के लिए एक साथ उपयोगकर्ताओं के बहुत बड़े आवेगों से निपटना होगा, जिन्हें अधिकृत होने की आवश्यकता है। अपनी वर्तमान स्थिति में, यह एक 32-कोर AWS उदाहरण के लिए पूरी तरह से अपंग है।

(ध्यान दें कि हम Nginx को एक रिवर्स प्रॉक्सी के रूप में उपयोग कर रहे हैं)

प्रतिक्रिया को केवल कैश नहीं किया जा सकता है, सबसे खराब स्थिति में, हमें यह जांचना चाहिए कि क्या उपयोगकर्ता को उनके जेडब्ल्यूटी को डिकोड करके प्रमाणित किया गया है। इसके लिए हमें लारवेल 4 की फायरिंग करनी होगी, जो ज्यादातर सहमत होगा, धीमा है , यहां तक ​​कि PHP-FPM और OpCache सक्षम है। यह ज्यादातर विषम बूटस्ट्रैपिंग चरण के कारण है।

एक सवाल पूछ सकता है "अगर आप जानते हैं कि यह एक मुद्दा बनने जा रहा है तो आपने पहली बार में PHP और Laravel का उपयोग क्यों किया?" - लेकिन उस निर्णय पर वापस जाने के लिए अब बहुत देर हो चुकी है!

संभावित समाधान

एक समाधान जो आगे रखा गया है, वह है लारवेल से प्रामाणिक मॉड्यूल को एक हल्के बाहरी मॉड्यूल (सी की तरह कुछ तेजी से लिखा गया) को निकालने के लिए, जिसकी ज़िम्मेदारी जेडब्ल्यूटी को डिकोड करना और यह तय करना है कि उपयोगकर्ता प्रमाणित है या नहीं।

अनुरोध का प्रवाह होगा:

  1. जाँच करें कि क्या कैश हिट हुआ (यदि सामान्य रूप से PHP में पास नहीं हुआ)
  2. टोकन को डिकोड करें
  3. जाँच करें कि क्या यह वैध है
  4. यदि मान्य है , तो कैश से सेवा करें
  5. यदि अमान्य है , तो Nginx को बताएं, और फिर Nginx सामान्य रूप से निपटने के लिए PHP में अनुरोध पारित करेगा।

यह हमें एक ही उपयोगकर्ता के लिए इस अनुरोध को पूरा करने के बाद PHP को हिट करने की अनुमति नहीं देगा और इसके बजाय एक हल्के मॉड्यूल तक पहुंचने के लिए JWTs को डिकोड करने और इस प्रकार के किसी भी अन्य कैविएट के साथ गड़बड़ करने के लिए पहुंच जाएगा।

मैं इस कोड को सीधे Nginx HTTP एक्सटेंशन मॉड्यूल के रूप में लिखने की सोच रहा था।

चिंताओं

मेरी चिंता यह है कि मैंने ऐसा पहले कभी नहीं देखा है और सोचा है कि क्या कोई बेहतर तरीका है।

इसके अलावा, दूसरा आप किसी भी उपयोगकर्ता विशिष्ट सामग्री को पेज पर जोड़ते हैं, यह पूरी तरह से इस विधि को मारता है।

वहाँ एक और सरल समाधान Nginx में सीधे उपलब्ध है? या हमें वार्निश की तरह कुछ और विशेष उपयोग करना होगा?

मेरे सवाल:

क्या उपरोक्त समाधान समझ में आता है?

यह सामान्य रूप से कैसे किया जाता है?

क्या एक समान या बेहतर प्रदर्शन लाभ प्राप्त करने का एक बेहतर तरीका है?


मैं इसी तरह की समस्या से जूझ रहा हूं। विचारों के एक जोड़े) एक Nginx मॉड्यूल विकसित करने की आवश्यकता को समाप्त करते हुए, Nginx Cort_request आपके प्रमाणीकरण microservice को बंद करने में सक्षम हो सकता है। ख) वैकल्पिक रूप से, आपका माइक्रोसॉफ़्ट प्रमाणित उपयोगकर्ताओं को एक अस्थायी URL पर पुनर्निर्देशित कर सकता है जो सार्वजनिक, सुगम्य और अस्वीकार्य है, लेकिन PHP बैकएंड द्वारा सीमित अवधि (कैश अवधि) के लिए मान्य होने के लिए मान्य किया जा सकता है। यह कुछ सुरक्षा का त्याग करता है, यदि अस्थायी URL एक अविश्वसनीय उपयोगकर्ता के लिए लीक हो जाता है, तो वे उस सीमित अवधि के लिए सामग्री का उपयोग कर सकते हैं, जैसे कि OAuth बियरर टोकन।
जेम्स

क्या आप इसके समाधान के साथ आए? मैं एक ही चीज़ का सामना कर रहा हूँ
timbroder

पता चलता है कि अनुकूलित बैकएंड नोड्स का एक बड़ा क्लस्टर होने से, हम लोड से निपटने में सक्षम थे - लेकिन मुझे इस दृष्टिकोण में एक बड़ी लागत बचत समाधान दीर्घकालिक होने का भरोसा है। यदि आप कुछ प्रतिक्रियाओं को जानते हैं जो आप पहले से सेवा कर सकते हैं, यदि आप अनुरोधों की आमद से पहले कैश को गर्म करते हैं, तो बैकएंड संसाधन बचत और विश्वसनीयता लाभ बहुत अधिक होगा।
यमोजीमबो

जवाबों:


9

मैं इसी तरह के एक मुद्दे को संबोधित करने की कोशिश कर रहा हूं। मेरे उपयोगकर्ताओं को उनके द्वारा किए जाने वाले प्रत्येक अनुरोध के लिए प्रमाणित करने की आवश्यकता है। मैं बैकएंड ऐप (जेडब्ल्यूटी टोकन की मान्यता) द्वारा उपयोगकर्ताओं को कम से कम एक बार प्रमाणित करने पर ध्यान केंद्रित कर रहा हूं, लेकिन उसके बाद, मैंने फैसला किया कि मुझे अब बैकएंड की आवश्यकता नहीं होनी चाहिए।

मैंने किसी भी Nginx प्लगइन की आवश्यकता से बचने के लिए चुना जो डिफ़ॉल्ट रूप से शामिल नहीं है। अन्यथा आप nginx-jwt या Lua स्क्रिप्टिंग की जांच कर सकते हैं और ये संभवत: महान समाधान होंगे।

प्रमाणीकरण को संबोधित करना

अब तक मैंने निम्नलिखित कार्य किए हैं:

  • प्रमाणीकरण का उपयोग करके Nginx को सौंप दिया auth_request। यह एक internalस्थान कहता है जो मेरे बैकएंड टोकन सत्यापन समापन बिंदु के अनुरोध को पारित करता है। यह अकेले अधिक संख्या में मान्यताओं को संभालने के मुद्दे को संबोधित नहीं करता है।

  • टोकन सत्यापन का परिणाम एक proxy_cache_key "$cookie_token";निर्देश का उपयोग करके कैश किया जाता है । सफल टोकन सत्यापन के बाद, बैकएंड एक Cache-Controlनिर्देश जोड़ता है जो कि नगनेक्स को केवल टोकन को 5 मिनट तक कैश करने के लिए कहता है। इस बिंदु पर, किसी भी टोकन का सत्यापन एक बार कैश में हो जाने के बाद, उसी उपयोगकर्ता / टोकन से बाद के अनुरोधों ने एंडरॉयड बैकएंड को स्पर्श नहीं किया है!

  • अवैध टोकन द्वारा संभावित बाढ़ के खिलाफ अपने बैकएंड ऐप की रक्षा करने के लिए, मैंने कैश को मान्यताओं से भी इनकार कर दिया, जब मेरा बैकएंड समापन बिंदु 401 लौटता है। ये ऐसे अनुरोधों के साथ संभावित रूप से नगनेक्स कैश भरने से बचने के लिए थोड़े समय के लिए कैश होते हैं।

मैंने कुछ अतिरिक्त सुधार जोड़े हैं जैसे कि एक लॉगआउट समापन बिंदु जो 401 को वापस करके एक टोकन को अमान्य करता है (जो कि नगनेक्स द्वारा कैश भी किया गया है) ताकि यदि उपयोगकर्ता लॉगआउट पर क्लिक करता है, तो टोकन अब भी समाप्त नहीं होने पर भी उपयोग नहीं किया जा सकता है।

इसके अलावा, मेरे Nginx कैश में प्रत्येक टोकन के लिए, JSON ऑब्जेक्ट के रूप में संबद्ध उपयोगकर्ता शामिल है, जो मुझे इस जानकारी की आवश्यकता होने पर DB से इसे प्राप्त करने से बचाता है; और मुझे टोकन डिक्रिप्ट करने से भी बचाता है।

टोकन आजीवन और ताज़ा टोकन के बारे में

5 मिनट के बाद, टोकन कैश में समाप्त हो जाएगा, इसलिए बैकएंड को फिर से क्वियर किया जाएगा। यह सुनिश्चित करने के लिए है कि आप एक टोकन को अमान्य कर सकते हैं, क्योंकि उपयोगकर्ता लॉग आउट करता है, क्योंकि यह समझौता किया गया है, और इसी तरह। बैकएंड में उचित कार्यान्वयन के साथ इस तरह की आवधिक पुनरावृत्ति, मुझे ताज़ा टोकन का उपयोग करने से बचाती है।

परंपरागत रूप से ताज़ा टोकन का उपयोग एक नए पहुंच टोकन का अनुरोध करने के लिए किया जाएगा; वे आपके बैकएंड में संग्रहीत किए जाएंगे और आप सत्यापित करेंगे कि एक्सेस टोकन के लिए एक अनुरोध एक ताज़ा टोकन के साथ किया गया है जो इस विशिष्ट उपयोगकर्ता के लिए डेटाबेस में आपके साथ मेल खाता है। यदि उपयोगकर्ता लॉग आउट करता है, या टोकन से समझौता किया जाता है, तो आप अपने DB में ताज़ा टोकन को हटा / अमान्य कर देंगे, ताकि अमान्य ताज़ा टोकन का उपयोग करके नए टोकन के लिए अगला अनुरोध विफल हो जाए।

संक्षेप में, ताज़ा टोकन में आमतौर पर एक लंबी वैधता होती है और हमेशा बैकएंड के खिलाफ जांच की जाती है। वे एक्सेस टोकन उत्पन्न करने के लिए उपयोग किए जाते हैं जिनकी बहुत कम वैधता (कुछ मिनट) है। ये एक्सेस टोकन सामान्य रूप से आपके बैकेंड तक पहुंचते हैं लेकिन आप केवल उनके हस्ताक्षर और समाप्ति तिथि की जांच करते हैं।

यहाँ मेरे सेटअप में, हम एक लंबी वैधता के साथ टोकन का उपयोग कर रहे हैं (घंटे या दिन हो सकते हैं), जिसमें एक एक्सेस टोकन और एक ताज़ा टोकन दोनों की समान भूमिका और विशेषताएं हैं। क्योंकि हमारे पास उनका सत्यापन और अमान्यकरण Nginx द्वारा कैश किया गया है, वे केवल 5 मिनट में एक बार बैकएंड द्वारा पूरी तरह से सत्यापित होते हैं। तो हम जोड़े हुए जटिलता के बिना ताज़ा टोकन (जल्दी से एक टोकन को अमान्य करने में सक्षम) का उपयोग करने का लाभ रखते हैं। और सरल मान्यता कभी भी आपके बैकएंड तक नहीं पहुंचती है जो कि Nginx कैश की तुलना में कम से कम 1 ऑर्डर है, भले ही वह केवल हस्ताक्षर और समाप्ति तिथि की जाँच के लिए उपयोग किया गया हो।

इस सेटअप के साथ, मैं अपने बैकएंड में प्रमाणीकरण को अक्षम कर सकता हूं, क्योंकि आने वाले सभी अनुरोध auth_requestइसे छूने से पहले नग्नेक्स निर्देश पर पहुंचते हैं ।

यदि आप किसी भी प्रकार के प्रति संसाधन प्राधिकरण को निष्पादित करने की आवश्यकता को पूरी तरह से हल नहीं करते हैं, लेकिन कम से कम आपने मूल प्राधिकरण भाग को सहेज लिया है। और आप टोकन को डिक्रिप्ट करने से भी बच सकते हैं या टोकन डेटा तक पहुंचने के लिए एक डीबी लुकअप कर सकते हैं क्योंकि नग्नेक्स कैश की गई प्रतिक्रिया का डेटा हो सकता है और इसे बैकएंड पर वापस भेज सकते हैं।

अब, मेरी सबसे बड़ी चिंता यह है कि मैं इसे साकार किए बिना सुरक्षा से संबंधित कुछ स्पष्ट तोड़ सकता हूं। यह कहा जा रहा है, किसी भी प्राप्त टोकन को अभी भी कम से कम एक बार Nginx द्वारा कैश किए जाने से पहले मान्य किया गया है। कोई भी टेम्पर्ड टोकन अलग होगा इसलिए कैश को हिट नहीं करेगा क्योंकि कैश की भी अलग होगी।

इसके अलावा, शायद यह ध्यान देने योग्य है कि एक वास्तविक विश्व प्रमाणीकरण एक अतिरिक्त नॉनस या कुछ और उत्पन्न करने (और सत्यापन) द्वारा टोकन चोरी के खिलाफ लड़ाई लड़ेगा।

यहाँ मेरे ऐप के लिए मेरे Nginx कॉन्फिग का सरलीकृत अर्क है:

# Cache for internal auth checks
proxy_cache_path /usr/local/var/nginx/cache/auth levels=1:2 keys_zone=auth_cache:10m max_size=128m inactive=10m use_temp_path=off;
# Cache for content
proxy_cache_path /usr/local/var/nginx/cache/resx levels=1:2 keys_zone=content_cache:16m max_size=128m inactive=5m use_temp_path=off;
server {
    listen 443 ssl http2;
    server_name ........;

    include /usr/local/etc/nginx/include-auth-internal.conf;

    location /api/v1 {
        # Auth magic happens here
        auth_request         /auth;
        auth_request_set     $user $upstream_http_X_User_Id;
        auth_request_set     $customer $upstream_http_X_Customer_Id;
        auth_request_set     $permissions $upstream_http_X_Permissions;

        # The backend app, once Nginx has performed internal auth.
        proxy_pass           http://127.0.0.1:5000;
        proxy_set_header     X-User-Id $user;
        proxy_set_header     X-Customer-Id $customer;
        proxy_set_header     X-Permissions $permissions;

        # Cache content
        proxy_cache          content_cache;
        proxy_cache_key      "$request_method-$request_uri";
    }
    location /api/v1/Logout {
        auth_request         /auth/logout;
    }

}

अब, आंतरिक /authसमापन बिंदु के लिए कॉन्फ़िगरेशन एक्सट्रैक्शन इस प्रकार है /usr/local/etc/nginx/include-auth-internal.conf:

# Called before every request to backend
location = /auth {
    internal;
    proxy_cache             auth_cache;
    proxy_cache_methods     GET HEAD POST;
    proxy_cache_key         "$cookie_token";
    # Valid tokens cache duration is set by backend returning a properly set Cache-Control header
    # Invalid tokens are shortly cached to protect backend but not flood Nginx cache
    proxy_cache_valid       401 30s;
    # Valid tokens are cached for 5 minutes so we can get the backend to re-validate them from time to time
    proxy_cache_valid       200 5m;
    proxy_pass              http://127.0.0.1:1234/auth/_Internal;
    proxy_set_header        Host ........;
    proxy_pass_request_body off;
    proxy_set_header        Content-Length "";
    proxy_set_header        Accept application/json;
}

# To invalidate a not expired token, use a specific backend endpoint.
# Then we cache the token invalid/401 response itself.
location = /auth/logout {
    internal;
    proxy_cache             auth_cache;
    proxy_cache_key         "$cookie_token";
    # Proper caching duration (> token expire date) set by backend, which will override below default duration
    proxy_cache_valid       401 30m;
    # A Logout requests forces a cache refresh in order to store a 401 where there was previously a valid authorization
    proxy_cache_bypass      1;

    # This backend endpoint always returns 401, with a cache header set to the expire date of the token
    proxy_pass              http://127.0.0.1:1234/auth/_Internal/Logout;
    proxy_set_header        Host ........;
    proxy_pass_request_body off;
}

सेवारत सामग्री को संबोधित करना

अब प्रमाणीकरण डेटा से अलग हो गया है। चूंकि आपने बताया था कि यह प्रत्येक उपयोगकर्ता के लिए समान था, इसलिए सामग्री को नगनेक्स (मेरे उदाहरण में, content_cacheज़ोन में) भी कैश किया जा सकता है ।

अनुमापकता

यह परिदृश्य बॉक्स से बाहर काम करता है यह मानते हुए कि आपके पास एक Nginx सर्वर है। एक वास्तविक दुनिया के परिदृश्य में आपके पास संभवतः उच्च उपलब्धता है, जिसका अर्थ है कई नगनेक्स उदाहरण, संभवतः आपके (लारवेल) बैकएंड एप्लिकेशन की मेजबानी भी करते हैं। उस स्थिति में, आपके उपयोगकर्ता जो भी अनुरोध करते हैं, वह आपके किसी भी नगनेक्स सर्वर को भेजा जा सकता है, और जब तक वे सभी स्थानीय रूप से टोकन को कैश नहीं कर लेते, वे इसे सत्यापित करने के लिए आपके बैकेंड तक पहुंचते रहेंगे। सर्वर की एक छोटी संख्या के लिए, इस समाधान का उपयोग करना अभी भी बड़े लाभ लाएगा।

हालांकि, यह ध्यान रखना महत्वपूर्ण है कि एकाधिक नगनेक्स सर्वर (और इस प्रकार कैश) के साथ आप सर्वर साइड पर लॉग आउट करने की क्षमता खो देते हैं क्योंकि आप इन सभी पर टोकन कैश को शुद्ध करने के लिए (ताज़ा करने के लिए) असमर्थ हैं, जैसे /auth/logoutमेरे उदाहरण में है। आप केवल 5mn टोकन कैश अवधि के साथ बचे हैं, जो आपके बैकएंड को जल्द ही बंद करने के लिए मजबूर करेगा, और Nginx को बताएगा कि अनुरोध अस्वीकार कर दिया गया है। लॉग आउट करते समय क्लाइंट पर टोकन हेडर या कुकी को हटाने के लिए एक आंशिक समाधान है।

किसी भी टिप्पणी का बहुत स्वागत और सराहना की जाएगी!


आप एक बहुत अधिक upvotes हो जाना चाहिए! बहुत मददगार, धन्यवाद!
गेरशोन पापी

"मैंने कुछ अतिरिक्त सुधार जोड़े हैं जैसे कि एक लॉगआउट समापन बिंदु जो 401 को वापस करके एक टोकन को अमान्य करता है (जिसे नगनेक्स द्वारा कैश भी किया जाता है) ताकि यदि उपयोगकर्ता लॉगआउट पर क्लिक करता है, तो टोकन समाप्त नहीं होने पर भी इसका उपयोग नहीं किया जा सकता है। " - यह चतुर है! , लेकिन क्या आप वास्तव में अपने बैकएंड में टोकन को ब्लैकलिस्ट कर रहे हैं, ताकि कैश कम या कुछ और हो जाए, तब भी उपयोगकर्ता उस विशेष टोकन के साथ लॉगिन नहीं कर सकता है?
gaurav5430

"हालांकि, यह ध्यान रखना महत्वपूर्ण है कि एकाधिक नगनेक्स सर्वर (और इस प्रकार कैश) के साथ आप सर्वर साइड पर लॉग आउट करने की क्षमता खो देते हैं क्योंकि आप इन सभी में टोकन कैश को शुद्ध करने के लिए (ताज़ा करने के लिए) असमर्थ हैं, मेरे उदाहरण में जैसे / सामान्य / लॉगआउट करता है। " क्या आप विस्तार से समझा सकते हैं?
गौरव ५०३०
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.