Node ve Express 4 ile temel HTTP kimlik doğrulaması


107

Görünüşe göre Express v3 ile temel HTTP kimlik doğrulaması yapmak önemsizdi:

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

Sürüm 4 (4.2 kullanıyorum) basicAuthara yazılımı kaldırdı , bu yüzden biraz sıkıştım. Aşağıdaki koda sahibim, ancak tarayıcının kullanıcıdan kimlik bilgilerini istemesine neden olmuyor, ki bu benim istediğim (ve eski yöntemin yaptığını tahmin ettiğim şey):

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
Utanmaz eklenti: Bunu kolaylaştıran ve ihtiyaç duyacağınız çoğu standart özelliğe sahip oldukça popüler bir modül kullanıyorum: express-basic-auth
LionC

Yakın zamanda @ LionC paketini çatalladım çünkü onu bir şirket projesi için ultra kısa bir süre içinde uyarlamak (bağlama duyarlı yetkilendiricileri etkinleştirmek) zorunda kaldım: npmjs.com/package/spresso-authy
castarco

Yanıtlar:


108

Vanilya JavaScript ile Basit Temel Kimlik Doğrulama (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

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

})

not: Bu "ara katman yazılımı" herhangi bir işleyicide kullanılabilir. Sadece next()mantığı kaldırın ve tersine çevirin. Aşağıdaki 1 ifade örneğine veya bu cevabın düzenleme geçmişine bakın .

Neden?

  • req.headers.authorization" Basic <base64 string>" değerini içerir , ancak boş da olabilir ve başarısız olmasını istemeyiz, bu nedenle|| ''
  • Düğüm bilmiyor atob()ve btoa()dolayısıylaBuffer

ES6 -> ES5

constadildir varçeşit ..
(x, y) => {...}sadece bir function(x, y) {...}
const [login, password] = ...split()sadece iki varbirinde atamaları

ilham kaynağı (paketleri kullanır)


Yukarıdakiler, süper kısa olması ve oyun alanı sunucunuza hızla yerleştirilmesi amaçlanan süper basit bir örnektir . Ancak yorumlarda belirtildiği gibi, şifreler iki nokta üst üste karakterleri de içerebilir . Bunu b64auth'dan doğru şekilde çıkarmak için bunu kullanabilirsiniz.:

  // 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(/(.*?):(.*)/) || []

Tek ifadede temel kimlik doğrulama

... Öte yandan, yalnızca bir veya birkaç giriş kullanırsanız, ihtiyacınız olan en düşük değer budur: (kimlik bilgilerini ayrıştırmanız bile gerekmez)

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)
}

Not: Hem "güvenli" hem de "genel" yollara ihtiyacınız var mı? express.routerBunun yerine kullanmayı düşünün .

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
Best of the lot ... :)
Anupam Basak

2
En .split(':')az bir iki nokta üst üste içeren şifreleri boğacağı için kullanmayın . Bu tür şifreler RFC 2617'ye göre geçerlidir .
Distortum

1
İki const [_, login, password] = strauth.match(/(.*?):(.*)/) || []nokta üst üste bölümü için RegExp'i de kullanabilirsiniz .
adabru

3
!==Parolaları karşılaştırmak için kullanmak sizi zamanlama saldırılarına karşı savunmasız bırakır. en.wikipedia.org/wiki/Timing_attack , sabit zaman dizesi karşılaştırması kullandığınızdan emin olun.
hraban

1
Kullanım Buffer.from() // for stringsveya Buffer.alloc() // for numbersolarak Buffer()güvenlik sorunları nedeniyle artık kullanılmıyor.
Bay Alien

71

TL; DR:

express.basicAuthgitti
basic-auth-connectkullanımdan kaldırıldı
basic-authmantığı yok
http-authabartı mı
express-basic-authistediğiniz şey

Daha fazla bilgi:

Express'i kullandığınız için express-basic-authara yazılımı kullanabilirsiniz .

Dokümanlara bakın:

Misal:

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: trueSeçeneği
anlamam biraz zaman

1
@VitaliiZurian İyi nokta - cevaba ekledim. Gösterdiğiniz için teşekkürler.
rsp

4
@rsp Bunu yalnızca belirli rotalara nasıl uygulayacağınızı biliyor musunuz?
Jorge L Hernandez

Başka bağımlılıkları eklemek istemiyorsanız, bu ... bir satırda elle temel kimlik doğrulama yazmak çok kolaydır
Qwerty

müşteri url'si nasıl görünür?
GGEv

57

Ara yazılımın çoğu v4'te Express çekirdeğinden çıkarıldı ve ayrı modüllere yerleştirildi. Temel kimlik doğrulama modülü burada: https://github.com/expressjs/basic-auth-connect

Örneğinizin sadece şuna değiştirilmesi gerekiyor:

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

19
Bu modül kullanımdan kaldırıldığını iddia ediyor (önerdiği alternatif tatmin edici görünmese de)
Arnout Engelen

3
^^ yoğun bir şekilde belgelenmemiş olduğu gibi kesinlikle tatmin edici değil. ara yazılım olarak kullanımın sıfır örneği, muhtemelen bunun için iyidir, ancak çağrı kullanılamaz. Verdikleri örnek genellik açısından harikadır, ancak kullanım bilgisi için değildir.
Wylie Kulik

Evet, bu kullanımdan kaldırıldı ve önerilenin dokümanlar için yetersiz olmasına rağmen, kod çok basittir github.com/jshttp/basic-auth/blob/master/index.js
Loourr

1
Bu cevaptabasic-auth kütüphaneyi nasıl kullanacağımı
anlattım

Şifrenin kodda açık metne koyulmasına dayanan bir modül nasıl olur ? En azından base64 ile karşılaştırarak onu gizlemek marjinal olarak daha iyi görünüyor.
user1944491

33

basicAuthCevabı bulmak için orijinalin kodunu kullandım :

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
bu modül kullanımdan kaldırılmış olarak kabul edilir, onun yerine jshttp / basic-auth kullanın (aynı api yani cevap hala geçerlidir)
Michael

32

Ekspres 4.0'da http-auth ile temel kimlik doğrulamasını değiştirdim , kod:

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
Bu tam anlamıyla tak ve çalıştır. Mükemmel.
sidonaldson

20

Bunu yapmak için birden fazla modül var gibi görünüyor, bazıları kullanımdan kaldırıldı.

Bu aktif görünüyor:
https://github.com/jshttp/basic-auth

İşte bir kullanım örneği:

// 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

Ara authyazılımı doğru yere koyduğunuzdan emin olun , bundan önceki hiçbir ara yazılım kimliği doğrulanmayacaktır.


Ben aslında 'temel-kimlik doğrulamasından' yanayım, isim kötü ama işlevsellik açısından 'temel-kimlik doğrulama'dan daha iyi. İkincisinin yaptığı tek şey, yetki başlığını ayrıştırmaktır. Hala implementprotokole kendiniz
girmelisiniz

Mükemmel! Bunun için teşekkür ederim. Bu işe yaradı ve her şeyi güzelce açıkladı.
Tania Rascia

Bunu denedim, ancak sürekli döngü üzerinden giriş yapmamı istiyor.
jdog

6

Herhangi bir modüle ihtiyaç duymadan temel yetkilendirmeyi uygulayabiliriz

//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);

Kaynak: - http://www.dotnetcurry.com/nodejs/1231/basic-authentication-using-nodejs


1

Express bu işlevi kaldırdı ve şimdi temel kimlik doğrulama kitaplığını kullanmanızı öneriyor .

İşte nasıl kullanılacağına dair bir örnek:

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)

Bu yola bir istek göndermek için, temel yetkilendirme için biçimlendirilmiş bir Yetkilendirme başlığı eklemeniz gerekir .

Bir curl isteği gönderirken önce base64 kodlamasını almalısınız name:passveya bu durumda aladdin:opensesameeşittirYWxhZGRpbjpvcGVuc2VzYW1l

Curl isteğiniz şu şekilde görünecektir:

 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);

Umarım sorunu çözecektir, ancak lütfen kodunuzun açıklamasını ekleyin, böylece kullanıcı gerçekten istediği şeyi mükemmel bir şekilde anlayacaktır.
Jaimil Patel
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.