नोड और एक्सप्रेस 4 के साथ बेसिक HTTP प्रमाणीकरण


107

ऐसा लगता है कि एक्सप्रेस v3 के साथ बुनियादी HTTP प्रमाणीकरण को लागू करना तुच्छ था:

app.use(express.basicAuth('username', 'password'));

संस्करण 4 (मैं 4.2 का उपयोग कर रहा हूं) ने basicAuthमिडलवेयर को हटा दिया , हालांकि, मैं थोड़ा फंस गया हूं। मेरे पास निम्न कोड है, लेकिन यह ब्राउज़र को क्रेडेंशियल्स के लिए उपयोगकर्ता को संकेत देने का कारण नहीं बनता है, जो कि मैं चाहूंगा (और मैंने जो पुरानी विधि की कल्पना की थी):

app.use(function(req, res, next) {
    var user = auth(req);

    if (user === undefined || user['name'] !== 'username' || user['pass'] !== 'password') {
        res.writeHead(401, 'Access invalid for user', {'Content-Type' : 'text/plain'});
        res.end('Invalid credentials');
    } else {
        next();
    }
});

2
बेशर्म प्लग: मैं एक काफी लोकप्रिय मॉड्यूल को बनाए रखता हूं जो कि आसान बनाता है और इसमें सबसे अधिक मानक विशेषताएं हैं
जिनकी

मैंने हाल ही में @LionC के पैकेज को forked किया क्योंकि मुझे एक कंपनी प्रोजेक्ट के लिए बहुत कम समय में इसे (संदर्भ-जागरूक अधिकारियों को सक्षम करना) अनुकूलित करना था: npmjs.com/package/spresso-authy
castcoco

जवाबों:


108

वेनिला जावास्क्रिप्ट (ES6) के साथ सरल मूल प्रामाणिक

app.use((req, res, next) => {

  // -----------------------------------------------------------------------
  // authentication middleware

  const auth = {login: 'yourlogin', password: 'yourpassword'} // change this

  // parse login and password from headers
  const b64auth = (req.headers.authorization || '').split(' ')[1] || ''
  const [login, password] = Buffer.from(b64auth, 'base64').toString().split(':')

  // Verify login and password are set and correct
  if (login && password && login === auth.login && password === auth.password) {
    // Access granted...
    return next()
  }

  // Access denied...
  res.set('WWW-Authenticate', 'Basic realm="401"') // change this
  res.status(401).send('Authentication required.') // custom message

  // -----------------------------------------------------------------------

})

नोट: इस "मिडलवेयर" का उपयोग किसी भी हैंडलर में किया जा सकता है। बस next()तर्क को हटा दें और उलट दें । देखें 1-बयान नीचे दिए गए उदाहरण के लिए, या संपादन इतिहास इस जवाब की।

क्यों?

  • req.headers.authorizationमान " Basic <base64 string>" होता है, लेकिन यह खाली भी हो सकता है और हम नहीं चाहते कि यह विफल हो, इसलिए अजीब कॉम्बो है|| ''
  • नोड पता नहीं है atob()और btoa()इसलिएBuffer

ईएस 6 -> ईएस 5

constबस है var.. एक तरह से
(x, y) => {...}बस है function(x, y) {...}
const [login, password] = ...split()सिर्फ दो है varएक में कार्य

प्रेरणा का स्रोत (संकुल का उपयोग करता है)


ऊपर एक सुपर सरल उदाहरण है जिसका उद्देश्य सुपर कम होना था और आपके खेल के मैदान सर्वर के लिए जल्दी से लागू होना चाहिए । लेकिन जैसा कि टिप्पणियों में बताया गया था, पासवर्ड में बृहदान्त्र वर्ण भी हो सकते हैं :। इसे सही ढंग से b64auth से निकालने के लिए , आप इसका उपयोग कर सकते हैं।

  // parse login and password from headers
  const b64auth = (req.headers.authorization || '').split(' ')[1] || ''
  const strauth = Buffer.from(b64auth, 'base64').toString()
  const splitIndex = strauth.indexOf(':')
  const login = strauth.substring(0, splitIndex)
  const password = strauth.substring(splitIndex + 1)

  // using shorter regex by @adabru
  // const [_, login, password] = strauth.match(/(.*?):(.*)/) || []

एक कथन में मूल कथन

... दूसरी ओर, यदि आप कभी केवल एक या बहुत कम लॉगिन का उपयोग करते हैं, तो यह नंगे न्यूनतम आपकी आवश्यकता है: (आपको सभी क्रेडेंशियल्स को पार्स करने की आवश्यकता नहीं है)

function (req, res) {
//btoa('yourlogin:yourpassword') -> "eW91cmxvZ2luOnlvdXJwYXNzd29yZA=="
//btoa('otherlogin:otherpassword') -> "b3RoZXJsb2dpbjpvdGhlcnBhc3N3b3Jk"

  // Verify credentials
  if (  req.headers.authorization !== 'Basic eW91cmxvZ2luOnlvdXJwYXNzd29yZA=='
     && req.headers.authorization !== 'Basic b3RoZXJsb2dpbjpvdGhlcnBhc3N3b3Jk')        
    return res.status(401).send('Authentication required.') // Access denied.   

  // Access granted...
  res.send('hello world')
  // or call next() if you use it as middleware (as snippet #1)
}

पुनश्च: क्या आपको "सुरक्षित" और "सार्वजनिक" दोनों रास्ते होने चाहिए? express.routerइसके बजाय उपयोग करने पर विचार करें ।

var securedRoutes = require('express').Router()

securedRoutes.use(/* auth-middleware from above */)
securedRoutes.get('path1', /* ... */) 

app.use('/secure', securedRoutes)
app.get('public', /* ... */)

// example.com/public       // no-auth
// example.com/secure/path1 // requires auth

2
सबसे अच्छा ... :)
अनुपम बसक

2
इसका उपयोग न करें .split(':')क्योंकि यह कम से कम एक बृहदान्त्र वाले पासवर्ड पर घुट जाएगा। ऐसे पासवर्ड RFC 2617 के अनुसार मान्य हैं ।
डिस्टॉर्टम

1
आप const [_, login, password] = strauth.match(/(.*?):(.*)/) || []बृहदान्त्र भाग के लिए RegExp का भी उपयोग कर सकते हैं ।
adabru

3
!==पासवर्ड की तुलना करने के लिए उपयोग करने से आप समय के हमलों की चपेट में आ जाते हैं। en.wikipedia.org/wiki/Timing_attack सुनिश्चित करें कि आप एक निरंतर समय स्ट्रिंग तुलना का उपयोग करते हैं।
हरबन

1
सुरक्षा मुद्दों के कारण उपयोग किया जाता है Buffer.from() // for stringsया घटाया Buffer.alloc() // for numbersजाता Buffer()है।
श्री एलियन

71

टी एल; डॉ:

express.basicAuthचला गया है
basic-auth-connectबहिष्कृत है
basic-authकिसी भी तर्क नहीं है
http-authएक overkill है
express-basic-authआप क्या चाहते है

और जानकारी:

चूंकि आप एक्सप्रेस का उपयोग कर रहे हैं तो आप express-basic-authमिडलवेयर का उपयोग कर सकते हैं ।

डॉक्स देखें:

उदाहरण:

const app = require('express')();
const basicAuth = require('express-basic-auth');
 
app.use(basicAuth({
    users: { admin: 'supersecret123' },
    challenge: true // <--- needed to actually show the login dialog!
}));

17
challenge: trueविकल्प के बारे में जानने के लिए मुझे कुछ समय दिया
विटाली ज़्यूरियन

1
@VitaliiZुरियन अच्छा बिंदु - मैंने इसे उत्तर में जोड़ा। इस पर ध्यान दिलाने के लिए धन्यवाद।
आरपी

4
@rsp क्या आप जानते हैं कि इसे केवल विशिष्ट मार्गों पर कैसे लागू किया जाए?
जॉर्ज एल हर्नांडेज़

यदि आप अन्य निर्भरताओं को जोड़ना नहीं चाहते हैं, तो एक पंक्ति में हाथ से मूल नीति लिखना बहुत आसान है ...
Qwerty

क्लाइंट url कैसा दिखेगा?
ग्वेग

57

बहुत से मिडलवेयर को v4 में एक्सप्रेस कोर से बाहर निकाला गया, और अलग-अलग मॉड्यूल में डाला गया। मूल ऑरिजनल मॉड्यूल यहां है: https://github.com/expressjs/basic-auth-connect

आपके उदाहरण को इसे बदलने की आवश्यकता होगी:

var basicAuth = require('basic-auth-connect');
app.use(basicAuth('username', 'password'));

19
इस मॉड्यूल को पदावनत किए जाने का दावा किया गया है (हालाँकि इसका विकल्प यह असंतोषजनक लगता है)
अर्नौट एंगेलन

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

हाँ, यह एक पदावनत है, और जबकि अनुशंसित एक डॉक्स पर कम है, कोड बहुत सरल है github.com/jshttp/basic-auth/blob/master/index.js
लौरिया

1
मैंने इस उत्तरbasic-auth में पुस्तकालय का उपयोग करने का वर्णन किया है
Loourr

कोड में स्पष्ट पाठ में पासवर्ड डालने के आधार पर एक पूरा मॉड्यूल कैसे मौजूद है ?? बेस 64 में तुलना करके कम से कम इसे अस्पष्ट रूप से बेहतर लगता है।
11:19 बजे user1944491

33

मैंने basicAuthउत्तर खोजने के लिए मूल के लिए कोड का उपयोग किया :

app.use(function(req, res, next) {
    var user = auth(req);

    if (user === undefined || user['name'] !== 'username' || user['pass'] !== 'password') {
        res.statusCode = 401;
        res.setHeader('WWW-Authenticate', 'Basic realm="MyRealmName"');
        res.end('Unauthorized');
    } else {
        next();
    }
});

10
इस मॉड्यूल को पदावनत माना जाता है, इसके बजाय jshttp / बुनियादी-मूल का उपयोग करें (वही एपीआई तो जवाब अभी भी लागू होता है)
माइकल

32

मैं एक्सप्रेस 4.0 में http- के साथ मूल प्रमाणीकरण में बदल गया , कोड है:

var auth = require('http-auth');

var basic = auth.basic({
        realm: "Web."
    }, function (username, password, callback) { // Custom authentication method.
        callback(username === "userName" && password === "password");
    }
);

app.get('/the_url', auth.connect(basic), routes.theRoute);

1
यह वस्तुतः प्लग एंड प्ले है। Exellent।
sidonaldson

20

ऐसा करने के लिए कई मॉड्यूल प्रतीत हो रहे हैं, कुछ को हटा दिया गया है।

यह एक सक्रिय दिखता है:
https://github.com/jshttp/basic-auth

यहाँ एक उपयोग उदाहरण है:

// auth.js

var auth = require('basic-auth');

var admins = {
  'art@vandelay-ind.org': { password: 'pa$$w0rd!' },
};


module.exports = function(req, res, next) {

  var user = auth(req);
  if (!user || !admins[user.name] || admins[user.name].password !== user.pass) {
    res.set('WWW-Authenticate', 'Basic realm="example"');
    return res.status(401).send();
  }
  return next();
};




// app.js

var auth = require('./auth');
var express = require('express');

var app = express();

// ... some not authenticated middlewares

app.use(auth);

// ... some authenticated middlewares

सुनिश्चित करें कि आपने authमिडिलवेयर को सही जगह पर रखा है, इससे पहले किसी भी मिडलवेयर को प्रमाणित नहीं किया जाएगा।


मैं वास्तव में 'बेसिक-ऑर्ट-कनेक्ट' के पक्ष में हूं, नाम खराब है, लेकिन कार्यक्षमता के हिसाब से यह 'बेसिक-ऑवर' से बेहतर है। सभी बाद वाले करता है, पार्स प्राधिकरण हेडर है। आपको अभी भी implementअपने आप को प्रोटोकॉल देना होगा (उर्फ सही हेडर भेजें)
FDIM

उत्तम! इसके लिए शुक्रिया। यह काम किया और सब कुछ अच्छी तरह से समझाया।
तानिया रास्किया

मैंने यह कोशिश की, लेकिन यह मुझे निरंतर लूप के माध्यम से लॉगिन करने के लिए कहता रहता है।
jdog

6

हम किसी भी मॉड्यूल की आवश्यकता के बिना मूल प्राधिकरण को लागू कर सकते हैं

//1.
var http = require('http');

//2.
var credentials = {
    userName: "vikas kohli",
    password: "vikas123"
};
var realm = 'Basic Authentication';

//3.
function authenticationStatus(resp) {
    resp.writeHead(401, { 'WWW-Authenticate': 'Basic realm="' + realm + '"' });
    resp.end('Authorization is needed');

};

//4.
var server = http.createServer(function (request, response) {
    var authentication, loginInfo;

    //5.
    if (!request.headers.authorization) {
        authenticationStatus (response);
        return;
    }

    //6.
    authentication = request.headers.authorization.replace(/^Basic/, '');

    //7.
    authentication = (new Buffer(authentication, 'base64')).toString('utf8');

    //8.
    loginInfo = authentication.split(':');

    //9.
    if (loginInfo[0] === credentials.userName && loginInfo[1] === credentials.password) {
        response.end('Great You are Authenticated...');
         // now you call url by commenting the above line and pass the next() function
    }else{

    authenticationStatus (response);

}

});
 server.listen(5050);

स्रोत: - http://www.dotnetcurry.com/nodejs/1231/basic-authentication-using-nodexs


1

एक्सप्रेस ने इस कार्यक्षमता को हटा दिया है और अब आपको मूल- पुस्तकालय का उपयोग करने की सलाह देता है ।

यहाँ कैसे उपयोग करने का एक उदाहरण है:

var http = require('http')
var auth = require('basic-auth')

// Create server
var server = http.createServer(function (req, res) {
  var credentials = auth(req)

  if (!credentials || credentials.name !== 'aladdin' || credentials.pass !== 'opensesame') {
    res.statusCode = 401
    res.setHeader('WWW-Authenticate', 'Basic realm="example"')
    res.end('Access denied')
  } else {
    res.end('Access granted')
  }
})

// Listen
server.listen(3000)

इस मार्ग के लिए एक अनुरोध भेजने के लिए आपको मूल प्राधिकरण के लिए प्रारूपित एक शीर्ष लेख शामिल करना होगा ।

कर्ल अनुरोध भेजने से पहले आपको इस मामले में बेस 64 एनकोडिंग लेनी होगी name:passया जो इस मामले aladdin:opensesameमें बराबर हैYWxhZGRpbjpvcGVuc2VzYW1l

आपका कर्ल अनुरोध फिर दिखेगा:

 curl -H "Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l" http://localhost:3000/

0
function auth (req, res, next) {
  console.log(req.headers);
  var authHeader = req.headers.authorization;
  if (!authHeader) {
      var err = new Error('You are not authenticated!');
      res.setHeader('WWW-Authenticate', 'Basic');
      err.status = 401;
      next(err);
      return;
  }
  var auth = new Buffer.from(authHeader.split(' ')[1], 'base64').toString().split(':');
  var user = auth[0];
  var pass = auth[1];
  if (user == 'admin' && pass == 'password') {
      next(); // authorized
  } else {
      var err = new Error('You are not authenticated!');
      res.setHeader('WWW-Authenticate', 'Basic');      
      err.status = 401;
      next(err);
  }
}
app.use(auth);

आशा है कि यह समस्या को हल कर देगा लेकिन कृपया इसके साथ अपने कोड की व्याख्या जोड़ें ताकि उपयोगकर्ता को सही समझ मिल जाएगी जिसे वह वास्तव में चाहता है।
जयमिल पटेल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.