Базовая HTTP-аутентификация с Node и Express 4
Похоже, что реализовать базовую HTTP-аутентификацию в Express v3 было тривиально:
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();
}
});
10 ответов
Я использовал код для оригинала 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();
}
});
Простая базовая аутентификация с ванильным 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
TL; DR:
☒ express.basicAuth
ушел
☒ basic-auth-connect
устарела
☒ basic-auth
не имеет никакой логики
☒ http-auth
это перебор
☑ express-basic-auth
это то, что вы хотите
Больше информации:
Поскольку вы используете Express, то вы можете использовать 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!
}));
Большая часть промежуточного программного обеспечения была извлечена из ядра Express в v4 и помещена в отдельные модули. Основной модуль аутентификации находится здесь: https://github.com/expressjs/basic-auth-connect
Ваш пример просто нужно изменить на это:
var basicAuth = require('basic-auth-connect');
app.use(basicAuth('username', 'password'));
Я изменил в 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);
Кажется, для этого есть несколько модулей, некоторые устарели.
Этот выглядит активным:
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
промежуточное программное обеспечение в правильном месте, любое промежуточное программное обеспечение до этого не будет аутентифицировано.
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);
установите зависимость express-basic-auth:
npm i express-basic-auth
Требовать пакет аутентификации, в котором вы создаете свое приложение
const app = require('express')();
const basicAuth = require('express-basic-auth');
и настройте промежуточное ПО следующим образом:
app.use(basicAuth({
users: { 'my-username': 'my-password' },
challenge: true,
}));
Мы можем реализовать базовую авторизацию без необходимости какого-либо модуля
//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)
Чтобы отправить запрос по этому маршруту, необходимо включить заголовок авторизации, отформатированный для базовой аутентификации.
Посылая запрос curl сначала вы должны использовать base64 кодировку name:pass
или в этом случае aladdin:opensesame
который равен YWxhZGRpbjpvcGVuc2VzYW1l
Ваш запрос curl будет выглядеть следующим образом:
curl -H "Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l" http://localhost:3000/