Базовая аутентификация HTTP с узлом и Экспресс 4


похоже, что реализация базовой HTTP-аутентификации с помощью Express v3 была тривиальной:

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

версия 4 (я использую 4.2) удалил basicAuth middleware, хотя, так что я немного застрял. У меня есть следующий код, но он не заставляет браузер запрашивать у пользователя учетные данные, что я и хотел бы (и что я думаю, что старый метод сделал):

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();
    }
});
8 72

8 ответов:

много промежуточного программного обеспечения было вытащено из ядра Express в v4 и помещено в отдельные модули. Основной модуль auth находится здесь:https://github.com/expressjs/basic-auth-connect

ваш пример просто нужно изменить для этого:

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

простой основной Auth с ванильным JavaScript (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] = new Buffer(b64auth, 'base64').toString().split(':')

  // Verify login and password are set and correct
  if (!login || !password || login !== auth.login || password !== auth.password) {
    res.set('WWW-Authenticate', 'Basic realm="401"') // change this
    res.status(401).send('Authentication required.') // custom message
    return
  }

  // -----------------------------------------------------------------------
  // Access granted...
  next()

})

почему?

  • req.headers.authorization содержит значение "Basic <base64 string>", но он также может быть пустым, и мы не хотим, чтобы это плохо, отсюда и странная комбинация || ''
  • узел не знаю atob() и btoa(), отсюда Buffer

ES6 - > ES5

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 = new Buffer(b64auth, 'base64').toString()
  const splitIndex = strauth.indexOf(':')
  const login = strauth.substring(0, splitIndex)
  const password = strauth.substring(splitIndex + 1)

С другой стороны, если вы когда-либо используете только один или очень мало Логинов, это самый минимум, что вам нужно:
(вам не нужно анализировать учетные данные)

//btoa('yourlogin:yourpassword') -> "eW91cmxvZ2luOnlvdXJwYXNzd29yZA=="

// Verify login and password is correct
if (req.headers.authorization !== 'Basic eW91cmxvZ2luOnlvdXJwYXNzd29yZA==') {
  // ...send('Authentication required.')
  return
}

кстати, вам нужно иметь как безопасные, так и" общедоступные " пути? Рассмотрите возможность использования 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

Я изменил в express 4.0 обычную аутентификацию с http-auth, код:

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

я использовал код для оригинальной 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();
    }
});

там, кажется, несколько модулей, чтобы сделать это, некоторые из них устарели.

этот выглядит активным:
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 промежуточное программное обеспечение в правильном месте, любое промежуточное программное обеспечение до этого не будет аутентифицироваться.

TL; DR:

express.basicAuth нет
basic-auth-connect осуждается
basic-auth не имеет никакой логики
http-auth - это перебор
express-basic-auth то, что вы хотите

Подробнее:

так как вы используете Экспресс, то вы можете использовать express-basic-auth middleware.

посмотреть документы:

пример:

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

мы можем реализовать базовую авторизацию без необходимости какого-либо модуля

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

Express удалил эту функцию и теперь рекомендует использовать basic-auth библиотека.

вот пример того, как использовать:

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)

для отправки запроса на этот маршрут необходимо включить заголовок отформатирован для basic авторизации.

отправив запрос curl сначала вы должны взять base64 кодирование name:pass или в данном случае aladdin:opensesame что равно YWxhZGRpbjpvcGVuc2VzYW1l

ваш curl запрос будет выглядеть так:

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