हाल ही में, उन्होंने मुझे एक्सप्रेस.जेएस पर एक परियोजना के लिए समर्थन दिया। प्रोजेक्ट कोड का अध्ययन करते समय, मुझे प्रमाणीकरण / प्राधिकरण के साथ थोड़ा भ्रमित करने वाला काम मिला, जो कि, पासपोर्ट.जेएस लाइब्रेरी पर 99.999% मामलों की तरह आधारित था। इस कोड ने काम किया, और "काम - स्पर्श न करें" के सिद्धांत का पालन किया, मैंने इसे वैसे ही छोड़ दिया। जब कुछ दिनों बाद मुझे दो और प्राधिकरण रणनीतियों को जोड़ने का काम दिया गया। और फिर मुझे याद आने लगा कि मैं पहले से ही एक समान काम कर रहा था, और इसमें कोड की कई लाइनें थीं। पासपोर्ट.जेएस पर प्रलेखन के माध्यम से देखने के बाद, मैं लगभग यह समझने में असमर्थ था कि क्या और कैसे करना है, क्योंकि वहाँ वे मामलों पर विचार करते हैं जब बिल्कुल एक रणनीति का उपयोग किया जाता है, जिसके लिए, प्रत्येक के लिए व्यक्तिगत रूप से, उदाहरण दिए जाते हैं। लेकिन कई रणनीतियों को कैसे संयोजित करें, आपको लॉग इन () विधि (जो लॉगिन के समान है) का उपयोग करने की आवश्यकता क्यों है - यह अभी भी स्पष्ट नहीं किया गया है। इसलिए, अब समझने के लिए, और बार-बार उसी खोज को न दोहराएं, मैंने इन नोटों को अपने लिए संकलित किया।
थोड़ा सा इतिहास। प्रारंभ में, वेब एप्लिकेशन कुकीज़ के उपयोग से सत्रों का उपयोग करके दो प्रकार के प्रमाणीकरण / प्राधिकरण: 1) मूल और 2) का उपयोग करते थे। मूल प्रमाणीकरण / प्राधिकरण में, प्रत्येक अनुरोध में एक हेडर भेजा जाता है, और इस प्रकार क्लाइंट प्रमाणीकरण प्रत्येक अनुरोध में किया जाता है। सत्र का उपयोग करते समय, क्लाइंट प्रमाणीकरण केवल एक बार किया जाता है (तरीके बहुत अलग हो सकते हैं, जिसमें बेसिक, साथ ही नाम और पासवर्ड भी शामिल हैं, जो फॉर्म में भेजे जाते हैं, और हजारों अन्य तरीके जिन्हें पासपोर्ट के संदर्भ में रणनीति कहा जाता है)। मुख्य बात यह है कि प्रमाणीकरण के बाद, ग्राहक कुकी में (या कुछ कार्यान्वयन, सत्र डेटा में) सत्र पहचानकर्ता की पहचान करता है, और उपयोगकर्ता पहचानकर्ता सत्र डेटा में संग्रहीत होता है।
पहले आपको यह तय करने की आवश्यकता है कि क्या आप प्रमाणीकरण / प्राधिकरण के लिए अपने आवेदन में सत्र का उपयोग करेंगे। यदि आप एक मोबाइल एप्लिकेशन के लिए बैकएंड विकसित कर रहे हैं, तो सबसे अधिक संभावना नहीं है। यदि यह एक वेब एप्लिकेशन है, तो संभवत: हां। सत्रों का उपयोग करने के लिए, आपको कुकी-पार्सर, सत्र मिडलवेयर को सक्रिय करना होगा, और सत्र को आरंभ करना होगा:
const app = express(); const sessionMiddleware = session({ store: new RedisStore({client: redisClient}), secret, resave: true, rolling: true, saveUninitialized: false, cookie: { maxAge: 10 * 60 * 1000, httpOnly: false, }, }); app.use(cookieParser()); app.use(sessionMiddleware); app.use(passport.initialize()); app.use(passport.session());
यहां आपको कुछ महत्वपूर्ण स्पष्टीकरण देने की आवश्यकता है। यदि आप एक-दो साल में सभी रैम खाने के लिए रेडिस नहीं चाहते हैं, तो आपको सत्र डेटा को समय पर हटाने का ध्यान रखना होगा। इसके लिए मैक्सएज पैरामीटर जिम्मेदार है, जो कुकी और रेडिस में संग्रहीत मूल्य दोनों के लिए समान रूप से इस मूल्य को निर्धारित करता है। मूल्यों को फिर से सेट करना: सच, रोलिंग: सत्य, प्रत्येक नए अनुरोध (यदि आवश्यक हो) के साथ निर्दिष्ट अधिकतम मूल्य के साथ वैधता अवधि का विस्तार करता है। अन्यथा, ग्राहक सत्र समय-समय पर बाधित होगा। अंत में, saveUninitialized: गलत पैरामीटर रेडिस में खाली सत्र नहीं रखेगा। यह आपको अनावश्यक डेटा के साथ लालियों को बंद किए बिना, आवेदन के स्तर पर सत्रों और पासपोर्ट की शुरुआत को लागू करने की अनुमति देता है। मार्ग के स्तर पर, यह तभी समझ में आता है कि यदि पासपोर्ट.संयोजक () विधि को अलग-अलग मापदंडों के साथ कॉल करने की आवश्यकता होती है।
यदि सत्र का उपयोग नहीं किया जाएगा, तो आरंभीकरण काफी कम हो जाएगा:
app.use(passport.initialize());
इसके बाद, आपको एक रणनीति ऑब्जेक्ट बनाने की आवश्यकता है (जैसा कि पासपोर्ट.जेएस शब्दावली में प्रमाणीकरण विधि कहता है)। प्रत्येक रणनीति की अपनी कॉन्फ़िगरेशन विशेषताएं होती हैं। केवल एक चीज जो अपरिवर्तित बनी हुई है, वह है कॉलबैक फ़ंक्शन को स्ट्रेटेजिक कंस्ट्रक्टर में पास किया जाता है, जो उपयोगकर्ता ऑब्जेक्ट बनाता है, जो निम्न मिडिलवेयर कतारों के लिए अनुरोध के रूप में सुलभ है।
const jwtStrategy = new JwtStrategy(params, (payload, done) => UserModel.findOne({where: {id: payload.userId}}) .then((user = null) => { done(null, user); }) .catch((error) => { done(error, null); }) );
हमें इस बात से अच्छी तरह अवगत होना चाहिए कि यदि किसी सत्र का उपयोग नहीं किया जाता है, तो इस पद्धति को हर बार एक संरक्षित संसाधन तक पहुंचने के लिए कहा जाएगा, और एक डेटाबेस क्वेरी (उदाहरण के रूप में) अनुप्रयोग प्रदर्शन को महत्वपूर्ण रूप से प्रभावित करेगा।
इसके बाद, आपको रणनीति का उपयोग करने के लिए एक कमांड देने की आवश्यकता है। प्रत्येक रणनीति का एक डिफ़ॉल्ट नाम होता है। लेकिन यह स्पष्ट रूप से सेट किया जा सकता है, जो विभिन्न मापदंडों और कॉलबैक फ़ंक्शन के तर्क के साथ एक रणनीति का उपयोग करने की अनुमति देता है:
passport.use('jwt', jwtStrategy); passport.use('simple-jwt', simpleJwtStrategy);
अगला, संरक्षित मार्ग के लिए, आपको एक प्रमाणीकरण रणनीति और एक महत्वपूर्ण सत्र पैरामीटर (डिफ़ॉल्ट सत्य है) निर्धारित करने की आवश्यकता है:
const authenticate = passport.authenticate('jwt', {session: false}); router.use('/hello', authenticate, (req, res) => { res.send('hello'); });
यदि सत्र का उपयोग नहीं किया जाता है, तो प्रमाणीकरण को सभी प्रतिबंधित एक्सेस मार्गों द्वारा संरक्षित किया जाना चाहिए। यदि सत्र का उपयोग किया जाता है, तो प्रमाणीकरण एक बार होता है, और इसके लिए एक विशेष मार्ग निर्धारित किया जाता है, उदाहरण के लिए लॉगिन:
const authenticate = passport.authenticate('local', {session: true}); router.post('/login', authenticate, (req, res) => { res.send({}) ; }); router.post('/logout', mustAuthenticated, (req, res) => { req.logOut(); res.send({}); });
सत्र का उपयोग करते समय, संरक्षित मार्गों पर, एक नियम के रूप में, बहुत संक्षिप्त मिडलवेयर (जो किसी कारण से पासपोर्ट.जेएस लाइब्रेरी में शामिल नहीं होता है) का उपयोग किया जाता है:
function mustAuthenticated(req, res, next) { if (!req.isAuthenticated()) { return res.status(HTTPStatus.UNAUTHORIZED).send({}); } next(); }
इसलिए, एक अंतिम क्षण था - सत्र का क्रमांकन और विचलन। सत्र से / के लिए ऑब्जेक्ट का।
passport.serializeUser((user, done) => { done(null, user.id); }); passport.deserializeUser((id, done) => { UserModel.findOne({where: {id}}).then((user) => { done(null, user); return null; }); });
मैं एक बार फिर इस बात पर जोर देना चाहता हूं कि सीरियलाइजेशन और डिसेरिएलाइजेशन केवल उन रणनीतियों के साथ काम करता है जिनके लिए {सत्र: सच} विशेषता सेट की गई है। प्रमाणीकरण के तुरंत बाद एक बार सीरियलाइज़ेशन किया जाएगा। इसलिए, सत्र में संग्रहीत डेटा को अपडेट करना बहुत समस्याग्रस्त होगा, जिसके संबंध में केवल उपयोगकर्ता आईडी (जो नहीं बदलता है) को बचाया जाता है। सुरक्षित मार्ग के लिए हर अनुरोध पर निर्विवाद रूप से प्रदर्शन किया जाएगा। इस संबंध में, डेटाबेस क्वेरी (उदाहरण में) आवेदन प्रदर्शन को काफी प्रभावित करती है।
नोट। यदि आप एक ही समय में कई कई रणनीतियों का उपयोग करते हैं, तो इन सभी रणनीतियों के लिए एक ही क्रमांकन / डिसेरिएलाइज़ेशन कोड काम करेगा। उस रणनीति को ध्यान में रखना जिसके लिए प्रमाणीकरण किया गया था, उदाहरण के लिए, आप उपयोगकर्ता ऑब्जेक्ट में एक रणनीति विशेषता शामिल कर सकते हैं। विभिन्न मूल्यों के साथ कई बार इनिशियलाइज़ () पद्धति को कॉल करने का कोई मतलब नहीं है। यह अभी भी अंतिम कॉल से मानों के साथ फिर से लिखा जाएगा।
यह कहानी का अंत हो सकता है। क्योंकि जो कहा गया है, इसके अलावा, व्यवहार में, कुछ और की आवश्यकता नहीं है। हालाँकि, फ्रंट-एंड डेवलपर्स के अनुरोध पर, मुझे त्रुटि के विवरण के साथ एक वस्तु को 401 प्रतिक्रिया में जोड़ना पड़ा (डिफ़ॉल्ट रूप से, यह "अनधिकृत" लाइन है)। और यह, जैसा कि यह निकला, बस नहीं किया जा सकता है। ऐसे मामलों के लिए, आपको लाइब्रेरी के मूल में थोड़ा गहरा होना चाहिए, जो इतना अच्छा नहीं है। Passport.authenticate विधि में एक तीसरा वैकल्पिक पैरामीटर है: हस्ताक्षर फ़ंक्शन (त्रुटि, उपयोगकर्ता, जानकारी) के साथ एक कॉलबैक फ़ंक्शन। छोटी समस्या यह है कि इस फ़ंक्शन को न तो प्रतिक्रिया ऑब्जेक्ट और न ही किया गया कोई फ़ंक्शन () / अगला () पास किया जाता है, और इसलिए आपको इसे मिडलवेयर में बदलना होगा:
route.post('/hello', authenticate('jwt', {session: false}), (req, res) => { res.send({}) ; }); function authenticate(strategy, options) { return function (req, res, next) { passport.authenticate(strategy, options, (error, user , info) => { if (error) { return next(error); } if (!user) { return next(new TranslatableError('unauthorised', HTTPStatus.UNAUTHORIZED)); } if (options.session) { return req.logIn(user, (err) => { if (err) { return next(err); } return next(); }); } req.user = user; next(); })(req, res, next); }; }
उपयोगी लिंक:
1)
toon.io/understanding-passportjs-authentication-flow2)
habr.com/post/2012063)
habr.com/company/ruvds/blog/3354344)
habr.com/post/2629795)
habr.com/company/Voximplant/blog/3231606)
habr.com/company/dataart/blog/2628177)
tools.ietf.org/html/draft-ietf-oauth-pop-altecture-088)
oauth.net/articles/authenticationapapacy@gmail.com
4 जनवरी, 2019