бібліотеки автентифікації користувача для node.js?


274

Чи існують бібліотеки автентифікації користувачів для node.js? Зокрема, я шукаю те, що може зробити автентифікацію пароля для користувача (використовуючи користувацький БД auth auth) та пов’язати цього користувача з сеансом.

Перш ніж написати авторську бібліотеку, я зрозумів, що побачу, чи знають люди про існуючі бібліотеки. Не вдалося знайти нічого очевидного за допомогою google-пошуку.

-Шреї


Для пошуку: Щось еквівалентне omniauth(рейки) або пітон social-auth. Користувачі PHP (та інших поширених мов веб-серверів) також можуть додавати їх еквівалент.
forivall

Відповіді:


233

Якщо ви шукаєте рамку автентифікації для Connect або Express, Passport варто вивчити: https://github.com/jaredhanson/passport

(Розголошення: я розробник паспорта)

Я розробив паспорт після того, як дослідив як підключення, так і авт. Хоча вони обидва чудові модулі, вони не відповідали моїм потребам. Мені хотілося чогось більш легкого і ненав'язливого.

Паспорт розбивається на окремі модулі, тому ви можете вибрати лише те, що вам потрібно (OAuth, лише за потреби). Паспорт також не встановлює жодних маршрутів у вашій програмі, що дає вам можливість вирішувати, коли і де ви хочете перевірити автентифікацію, а також гачки контролювати, що відбувається, коли аутентифікація проходить успішно або не вдалося.

Наприклад, ось двоетапний процес налаштування автентифікації на основі форми (ім’я користувача та пароля):

passport.use(new LocalStrategy(
  function(username, password, done) {
    // Find the user from your DB (MongoDB, CouchDB, other...)
    User.findOne({ username: username, password: password }, function (err, user) {
      done(err, user);
    });
  }
));

app.post('/login', 
  passport.authenticate('local', { failureRedirect: '/login' }),
  function(req, res) {
    // Authentication successful. Redirect home.
    res.redirect('/');
  });

Для аутентифікації доступні додаткові стратегії через Facebook, Twitter тощо. Користувацькі стратегії можна підключати, якщо необхідно.


Серед усіх автентичних пакетів для вузла я вибрав паспорт. Це добре документоване і просте у використанні, а також підтримує більше стратегій.
техно-людина

На даний момент я використовую паспорт для прототипу, і не рекомендую його, оскільки він, здається, не підтримується, а дизайн не дуже хороший. Наприклад, він змушує вас використовувати connect-flash, коли він може просто використовувати req.session.messages, а паспорт-google, розміщений на веб-сайті, застарів, оскільки він використовує Google OpenId, який є застарілим, і немає посилання на паспорт- google-oauth, який повинен його замінити. Також це підпис зворотного дзвінка після аутентифікації: done(null,false,{ message:'Incorrect username.' })це жахливо, оскільки ми не знаємо, які всі ці параметри.
eloone

1
@eloone Мені потрібно оновити документи, щоб вказати на нові методи аутентифікації, які зараз надає перевагу Google. Як ви згадуєте, для них існує підтримка, і вони працюють добре. Що стосується питань дизайну, паспорт не змушує вас використовувати connect-flash, а аргументи, які ви згадуєте, задокументовані в путівнику. Якщо вам потрібна допомога в розумінні, є форуми, де люди можуть допомогти і відповісти на ваші запитання.
Джаред Гансон

Не дарма - але я щойно закінчив підключення паспорта (використав приклади). Супер легко! Я усвідомлюю, що минуло кілька років з моменту останніх коментарів. Я б порекомендував когось поглянути.
терари

89

Сесія + Якщо

Я здогадуюсь, що причина, що ви не знайшли багато хороших бібліотек, полягає в тому, що використання бібліотеки для аутентифікації здебільшого сконструйовано.

Що ви шукаєте, це просто прив'язка сесії :) Сесія з:

if login and user == xxx and pwd == xxx 
   then store an authenticated=true into the session 
if logout destroy session

Це воно.


Я не згоден з вашим висновком, що плагін connect-auth - це шлях.

Я також використовую connect, але я не використовую connect-auth з двох причин:

  1. IMHO розриває підключення-автентично дуже потужна та зручна для читання лучна кільцева архітектура підключення. Недоступ - моя думка :). Тут ви можете знайти дуже гарну та коротку статтю про те, як підключити роботу та ідею кільця цибулі тут .

  2. Якщо ви - як написано - просто хочете використовувати базовий або http-логін із базою даних або файлом. Підключення-auth занадто велике. Це більше для таких речей, як OAuth 1.0, OAuth 2.0 & Co


Дуже проста автентифікація з підключенням

(Завершено. Просто виконайте його для тестування, але якщо ви хочете використовувати його у виробництві, обов'язково використовуйте https) (І щоб бути сумісним з принципом REST, ви повинні використовувати POST-Request замість GET-Request b / c ти міняєш штат :)

var connect = require('connect');
var urlparser = require('url');

var authCheck = function (req, res, next) {
    url = req.urlp = urlparser.parse(req.url, true);

    // ####
    // Logout
    if ( url.pathname == "/logout" ) {
      req.session.destroy();
    }

    // ####
    // Is User already validated?
    if (req.session && req.session.auth == true) {
      next(); // stop here and pass to the next onion ring of connect
      return;
    }

    // ########
    // Auth - Replace this example with your Database, Auth-File or other things
    // If Database, you need a Async callback...
    if ( url.pathname == "/login" && 
         url.query.name == "max" && 
         url.query.pwd == "herewego"  ) {
      req.session.auth = true;
      next();
      return;
    }

    // ####
    // This user is not authorized. Stop talking to him.
    res.writeHead(403);
    res.end('Sorry you are not authorized.\n\nFor a login use: /login?name=max&pwd=herewego');
    return;
}

var helloWorldContent = function (req, res, next) {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('authorized. Walk around :) or use /logout to leave\n\nYou are currently at '+req.urlp.pathname);
}

var server = connect.createServer(
      connect.logger({ format: ':method :url' }),
      connect.cookieParser(),
      connect.session({ secret: 'foobar' }),
      connect.bodyParser(),
      authCheck,
      helloWorldContent
);

server.listen(3000);

ПРИМІТКА

Я писав цю заяву більше року тому і наразі не має активних проектів у вузлах. Тому в Express можуть бути зміни API-змін. Будь ласка, додайте коментар, якщо я щось зміню.


Чому connect-auth порушує схему лука / шарів? це тому, що він не використовує next ()? Можливо?
jpstrikesback

3
Так. Він повинен використовувати next (), тому що це ідея підключення. Connect має архітектуру шарів / форму структури коду. І кожен шар може зупинити виконання запиту, не викликаючи next (). Якщо ми говоримо про автентифікацію: рівень аутентифікації перевірить, чи користувач має правильні дозволи. Якщо все добре, шар викликає next (). Якщо ні, то цей рівень авторства створює помилку і не викликає наступного ().
Маттіас

чоловіче, це саме те, що я шукав. connect-auth давав мені трохи нетравлення. Я вперше увійшов у свій додаток. дуже дякую.
Енді Рей

7
Це все ще не допомагає відповісти, як підключитися до бекенда бази даних (бажано із зашифрованими паролями). Я ціную ваш коментар, що ця бібліотека перероблена, але, безумовно, є така, яка не є. Крім того, якби я хотів написати власну систему аутентифікації, я використав би Struts на Java. подібно до ОП, я хочу знати, які плагіни будуть робити це для мене в 1 рядку коду.
hendrixski

4
чудова відповідь Nivoc. Не працює з останніми версіями connect tho. Мені довелося змінити ... cookieDecoder () -> cookieParser () та bodyDecoder () -> bodyParser () та видалити наступний () виклик з функції helloWorldContent, оскільки я отримував помилку "Не можу встановити заголовки після того, як вони відправляються '
Майкл Даусман

26

Схоже, плагін connect-auth до проміжного програмного забезпечення підключення саме те, що мені потрібно: http://wiki.github.com/ciaranj/connect-auth/creating-a-form-based-strategy

Я використовую Express [ http://expressjs.com ], тому плагін підключення дуже добре вписується, оскільки Express є підкласом (добре - прототипом) від connect


1
ей, чи є у вас приклад того, що ви робили? просто вимагаючи підключення-auth та виклику ".authenticate" на "req" повертає "TypeError: Об'єкт # не має методу" автентифікувати "для мене.
Міша Рейзлін

1
IMHO Цей плагін дуже важкий для простої автентифікації http
Маттіас

І цей плагін працює проти підключення архітектури кільця цибулі
Маттіас

14

Я в основному шукав те саме. Зокрема, я хотів наступного:

  1. Використовувати express.js, який завершує функцію проміжного програмного забезпечення Connect
  2. Аутентифікація на основі форми
  3. Гранульований контроль над тим, які маршрути аутентифіковані
  4. Резервна база даних для користувачів / паролів
  5. Використовуйте сеанси

Що я в кінцевому підсумку робив, це створити власну функцію проміжного програмного забезпечення, check_authяку я передаю як аргумент кожному маршруту, який я хочу підтвердити. check_authпросто перевіряє сеанс, і якщо користувач не ввійшов у систему, перенаправляє їх на сторінку входу, наприклад:

function check_auth(req, res, next) {

  //  if the user isn't logged in, redirect them to a login page
  if(!req.session.login) {
    res.redirect("/login");
    return; // the buck stops here... we do not call next(), because
            // we don't want to proceed; instead we want to show a login page
  }

  //  the user is logged in, so call next()
  next();
}

Потім для кожного маршруту я переконуюсь, що ця функція передається як проміжне програмне забезпечення. Наприклад:

app.get('/tasks', check_auth, function(req, res) {
    // snip
});

Нарешті, нам потрібно реально обробити процес входу. Це прямо:

app.get('/login', function(req, res) {
  res.render("login", {layout:false});
});

app.post('/login', function(req, res) {

  // here, I'm using mongoose.js to search for the user in mongodb
  var user_query = UserModel.findOne({email:req.body.email}, function(err, user){
    if(err) {
      res.render("login", {layout:false, locals:{ error:err } });
      return;
    }

    if(!user || user.password != req.body.password) {
      res.render("login",
        {layout:false,
          locals:{ error:"Invalid login!", email:req.body.email }
        }
      );
    } else {
      // successful login; store the session info
      req.session.login = req.body.email;
      res.redirect("/");
    }
  });
});

У будь-якому випадку, цей підхід був здебільшого розроблений таким, щоб бути гнучким та простим. Я впевнений, що існує безліч способів її вдосконалити. Якщо у вас є якісь, я дуже б хотів ваших відгуків.

EDIT: Це спрощений приклад. У виробничій системі ви ніколи не хочете зберігати та порівнювати паролі у простому тексті. Як зазначає коментатор, є вкладені файли, які допоможуть керувати безпекою пароля.


2
це добре, за винятком того, що ви повинні використовувати bcrypt для зберігання пароля (не простий текст у db). Тут є хороший пост про це: devsmash.com/blog/…
chovy


7

Ось код базової аутентифікації від одного з моїх проектів. Я використовую його проти CouchDB з додатковим автентичним кешем даних, але я зняв цей код.

Оберніть метод аутентифікації навколо обробки запиту та надайте другий зворотний дзвінок для невдалої аутентифікації. Зворотний виклик успіху отримає ім'я користувача як додатковий параметр. Не забувайте правильно обробляти запити з неправильними або відсутніми обліковими записами при зворотному виклику помилки:

/**
 * Authenticate a request against this authentication instance.
 * 
 * @param request
 * @param failureCallback
 * @param successCallback
 * @return
 */
Auth.prototype.authenticate = function(request, failureCallback, successCallback)
{
    var requestUsername = "";
    var requestPassword = "";
    if (!request.headers['authorization'])
    {
        failureCallback();
    }
    else
    {
        var auth = this._decodeBase64(request.headers['authorization']);
        if (auth)
        {
            requestUsername = auth.username;
            requestPassword = auth.password;
        }
        else
        {
            failureCallback();
        }
    }


    //TODO: Query your database (don't forget to do so async)


    db.query( function(result)
    {
        if (result.username == requestUsername && result.password == requestPassword)
        {
            successCallback(requestUsername);
        }
        else
        {
            failureCallback();
        }
    });

};


/**
 * Internal method for extracting username and password out of a Basic
 * Authentication header field.
 * 
 * @param headerValue
 * @return
 */
Auth.prototype._decodeBase64 = function(headerValue)
{
    var value;
    if (value = headerValue.match("^Basic\\s([A-Za-z0-9+/=]+)$"))
    {
        var auth = (new Buffer(value[1] || "", "base64")).toString("ascii");
        return {
            username : auth.slice(0, auth.indexOf(':')),
            password : auth.slice(auth.indexOf(':') + 1, auth.length)
        };
    }
    else
    {
        return null;
    }

};

Я хотів уникнути базового авт на користь форми на основі форми. Це, безумовно, елегантне рішення основної проблеми з авторством. Я думаю, що, можливо, я знайшов хорошу структуру auth, хоча (connect-auth - сидить на вершині connectjs)
shreddd

4

Іншим способом аутентифікації є Passwordless, модуль аутентифікації на основі лексем для експресу, який обходить проблему паролів [1]. Це швидко реалізується, не вимагає занадто великої кількості форм і забезпечує кращу безпеку для середнього користувача (повне розкриття: я автор).

[1]: Паролі застаріли


3

Минуло кілька років, і я хотів би представити своє рішення для аутентифікації для Express. Це називається Lockit . Ви можете знайти проект на GitHub та короткий вступ у моєму блозі .

Тож у чому відмінності існуючих рішень?

  • простий у використанні: настройка вашої БД, НПМ встановити, require('lockit'), lockit(app), зроблено
  • маршрути, які вже вбудовані (/ реєстрація, / вхід, / забутий пароль тощо)
  • перегляди, які вже вбудовані (засновані на Bootstrap, але ви можете легко використовувати власні подання)
  • він підтримує зв'язок JSON для ваших програм на одній сторінці AngularJS / Ember.js
  • він НЕ підтримує OAuth та OpenID. Тільки usernameі password.
  • вона працює з декількома базами даних (CouchDB, MongoDB, SQL) поза коробкою
  • у нього є тести (я не зміг знайти жодних тестів для гіпсокартону)
  • він активно підтримується (порівняно з кожним)
  • підтвердження електронної пошти та процес забутого пароля (надсилайте електронну пошту з маркером, не підтримується паспортом)
  • модульність: використовуйте лише те, що вам потрібно
  • гнучкість: налаштувати всі речі

Погляньте на приклади .


2

Існує проект під назвою Drywall, який реалізує систему входу користувачів за допомогою Passport, а також має адміністраторську панель управління користувачем. Якщо ви шукаєте повнофункціональну систему аутентифікації та управління користувачам, схожу на те, що є у Django, але для Node.js, це все. Я вважав, що це справді хороша відправна точка для створення програми для вузлів, яка вимагала системи автентифікації та управління користувачем. Дивіться відповідь Джареда Гансона для інформації про те, як працює паспорт.



1

Швидкий простий приклад використання mongo, для API, який забезпечує авторизацію користувача, наприклад Angular client

в app.js

var express = require('express');
var MongoStore = require('connect-mongo')(express);

// ...

app.use(express.cookieParser());
// obviously change db settings to suit
app.use(express.session({
    secret: 'blah1234',
    store: new MongoStore({
        db: 'dbname',
        host: 'localhost',
        port: 27017
    })
}));

app.use(app.router);

для вашого маршруту щось подібне:

// (mongo connection stuff)

exports.login = function(req, res) {

    var email = req.body.email;
    // use bcrypt in production for password hashing
    var password = req.body.password;

    db.collection('users', function(err, collection) {
        collection.findOne({'email': email, 'password': password}, function(err, user) {
            if (err) {
                res.send(500);
            } else {
                if(user !== null) {
                    req.session.user = user;
                    res.send(200);
                } else {
                    res.send(401);
                }
            }
        });
    });
};

Тоді у своїх маршрутах, які потребують авторизації, ви можете просто перевірити сеанс користувача:

if (!req.session.user) {
    res.send(403);
}

0

Ось нова бібліотека аутентифікації, яка використовує символи, розмічені часом. Маркери можна надсилати електронною поштою або надсилати текстові повідомлення без необхідності зберігати їх у базі даних. Він може бути використаний для аутентифікації без паролів або для двофакторної автентифікації.

https://github.com/vote539/easy-no-password

Розкриття: Я розробник цієї бібліотеки.


0

Якщо вам потрібна автентифікація на SSO (Single Sign On) з обліковим записом користувача Microsoft Windows. Ви можете спробувати https://github.com/jlguenego/node-expose-sspi .

Це дасть вам req.ssoоб’єкт, який містить всю інформацію про клієнта (логін, відображуване ім’я, sid, групи).

const express = require("express");
const { sso, sspi } = require("node-expose-sspi");

sso.config.debug = false;

const app = express();

app.use(sso.auth());

app.use((req, res, next) => {
  res.json({
    sso: req.sso
  });
});

app.listen(3000, () => console.log("Server started on port 3000"));

Відмова: Я автор node-expose-sspi.


0

солодкий-авт

Легкий модуль аутентифікації користувача з нульовою конфігурацією. Для цього не потрібна спеціальна база даних.

https://www.npmjs.com/package/sweet-auth

Це просто, як:

app.get('/private-page', (req, res) => {

    if (req.user.isAuthorized) {
        // user is logged in! send the requested page
        // you can access req.user.email
    }
    else {
        // user not logged in. redirect to login page
    }
})
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.