thư viện xác thực người dùng cho node.js?


274

Có bất kỳ thư viện xác thực người dùng hiện có cho node.js không? Cụ thể, tôi đang tìm kiếm thứ gì đó có thể xác thực mật khẩu cho người dùng (sử dụng DB phụ trợ tùy chỉnh) và liên kết người dùng đó với một phiên.

Trước khi tôi viết một thư viện auth, tôi đã hình dung mình sẽ xem mọi người có biết về các thư viện hiện có không. Không thể tìm thấy bất cứ điều gì rõ ràng thông qua một tìm kiếm google.

-Shreyas


Đối với khả năng tìm kiếm: Một cái gì đó tương đương với omniauth(đường ray) hoặc python social-auth. Người dùng PHP (và các ngôn ngữ máy chủ web phổ biến khác) cũng nên thoải mái thêm tương đương.
tạm biệt

Câu trả lời:


233

Nếu bạn đang tìm kiếm một khung xác thực cho Connect hoặc Express, Passport đáng để nghiên cứu: https://github.com/jaredhanson/passport

(Tiết lộ: Tôi là nhà phát triển Hộ chiếu)

Tôi đã phát triển Hộ chiếu sau khi điều tra cả kết nối-auth và everyauth. Mặc dù cả hai đều là những mô-đun tuyệt vời, nhưng chúng không phù hợp với nhu cầu của tôi. Tôi muốn một cái gì đó nhẹ hơn và không phô trương.

Hộ chiếu được chia thành các mô-đun riêng biệt, vì vậy bạn có thể chọn chỉ sử dụng những gì bạn cần (OAuth, chỉ khi cần thiết). Hộ chiếu cũng không gắn kết bất kỳ tuyến đường nào trong ứng dụng của bạn, cho phép bạn linh hoạt quyết định thời điểm và nơi bạn muốn xác thực và móc nối để kiểm soát những gì xảy ra khi xác thực thành công hay thất bại.

Ví dụ: đây là quy trình hai bước để thiết lập xác thực dựa trên mẫu (tên người dùng và mật khẩu):

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('/');
  });

Các chiến lược bổ sung có sẵn để xác thực qua Facebook, Twitter, v.v. Các chiến lược tùy chỉnh có thể được cắm vào, nếu cần thiết.


Trong số tất cả các gói auth cho nút tôi đã chọn hộ chiếu. Nó được ghi chép tốt và dễ sử dụng, và hỗ trợ nhiều chiến lược hơn.
người đàn ông công nghệ

Hiện tại tôi đang sử dụng hộ chiếu cho một nguyên mẫu và tôi không khuyên dùng vì nó dường như không được duy trì và thiết kế không được tốt lắm. Ví dụ: nó buộc bạn phải sử dụng kết nối flash khi đơn giản là nó có thể sử dụng req.session.messages và hộ chiếu-google được quảng cáo trên trang web đã lỗi thời vì nó sử dụng Google OpenId không được dùng nữa và không có liên kết đến hộ chiếu- google-oauth nên thay thế nó. Ngoài ra, đây là chữ ký của một cuộc gọi lại sau khi xác thực: done(null,false,{ message:'Incorrect username.' })thật tồi tệ vì chúng ta không biết tất cả các tham số đó là gì.
eloone

1
@eloone Tôi cần cập nhật các tài liệu để trỏ đến các phương thức xác thực mới mà Google hiện đang thích. Như bạn đề cập, hỗ trợ tồn tại cho những người đó và họ làm việc tốt. Đối với các câu hỏi về thiết kế, hộ chiếu không buộc bạn phải sử dụng đèn flash kết nối và các đối số bạn đề cập được ghi lại trong hướng dẫn. Nếu bạn cần trợ giúp để hiểu, có những diễn đàn nơi mọi người có thể hỗ trợ và trả lời câu hỏi của bạn.
Jared Hanson

Không phải là không có gì - nhưng tôi vừa hoàn thành việc cắm Hộ chiếu (đã sử dụng ví dụ được cung cấp). Siêu dễ! Tôi nhận ra rằng đã được một vài năm kể từ khi những bình luận gần đây nhất. Tôi muốn giới thiệu bất cứ ai hãy xem.
khủng khiếp

89

Phiên + Nếu

Tôi đoán lý do mà bạn chưa tìm thấy nhiều thư viện tốt là vì sử dụng thư viện để xác thực chủ yếu là quá kỹ thuật.

Những gì bạn đang tìm kiếm chỉ là một chất kết dính phiên :) Một phiên với:

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

đó là nó.


Tôi không đồng ý với kết luận của bạn rằng plugin kết nối-auth là cách để đi.

Tôi cũng đang sử dụng kết nối nhưng tôi không sử dụng kết nối-auth vì hai lý do:

  1. IMHO phá vỡ kết nối-auth kiến ​​trúc kết nối vòng rất mạnh mẽ và dễ đọc. Không đi - ý kiến ​​của tôi :). Bạn có thể tìm thấy một bài viết rất hay và ngắn về cách kết nối hoạt động và ý tưởng vòng hành tây ở đây .

  2. Nếu bạn - như đã viết - chỉ muốn sử dụng thông tin đăng nhập cơ bản hoặc http với cơ sở dữ liệu hoặc tệp. Connect-auth là cách quá lớn. Đó là nhiều hơn cho những thứ như OAuth 1.0, OAuth 2.0 & Co


Một xác thực rất đơn giản với kết nối

(Đã hoàn tất. Chỉ cần thực hiện thử nghiệm nhưng nếu bạn muốn sử dụng nó trong sản xuất, hãy đảm bảo sử dụng https) (Và để tuân thủ REST-Nguyên tắc tuân thủ, bạn nên sử dụng Yêu cầu POST thay vì B / c Yêu cầu GET bạn thay đổi trạng thái :)

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

GHI CHÚ

Tôi đã viết tuyên bố này hơn một năm trước và hiện tại không có dự án nút hoạt động. Vì vậy, có thể có các thay đổi API trong Express. Vui lòng thêm một bình luận nếu tôi nên thay đổi bất cứ điều gì.


Tại sao kết nối-auth phá vỡ mô hình củ hành / lớp? Có phải vì nó không sử dụng next ()? Có thể nó?
jpstrikesback

3
Đúng. Nó phải sử dụng next () vì đó là ý tưởng đằng sau kết nối. Connect có cấu trúc lớp / kiến ​​trúc mã. Và mỗi lớp có khả năng dừng thực thi yêu cầu bằng cách không gọi next (). Nếu chúng ta đang nói về xác thực: Một lớp xác thực sẽ kiểm tra xem người dùng có quyền chính xác hay không. Nếu mọi thứ đều ổn, lớp gọi next (). Nếu không, lớp auth này sẽ tạo ra lỗi và sẽ không gọi next ().
Matthias

người đàn ông, đây chính xác là những gì tôi đang tìm kiếm. kết nối-auth đã cho tôi một chút khó tiêu. Tôi mới đăng nhập vào ứng dụng của mình lần đầu tiên. cám ơn rất nhiều.
Andy Ray

7
Điều này vẫn không giúp trả lời cách kết nối với phụ trợ cơ sở dữ liệu (tốt nhất là với mật khẩu được mã hóa). Tôi đánh giá cao nhận xét của bạn rằng một thư viện này được thiết kế quá mức, nhưng chắc chắn có một thư viện không. Ngoài ra, nếu tôi muốn viết hệ thống xác thực của riêng mình, tôi đã sử dụng Struts trong Java. giống như OP, tôi muốn biết plugin nào sẽ làm điều đó cho tôi trong 1 dòng mã.
hendrixski

4
câu trả lời tuyệt vời Nivoc. Không hoạt động với các phiên bản mới nhất của kết nối tho. Tôi đã phải thay đổi ... cookieDecoder () -> cookieParser () và bodyDecoder () -> bodyParser () và xóa cuộc gọi () tiếp theo khỏi hàm helloWorldContent vì tôi gặp lỗi 'Không thể đặt tiêu đề sau chúng được gửi '
Michael Dausmann

26

Có vẻ như plugin kết nối-auth với phần mềm trung gian kết nối chính xác là những gì tôi cần: http://wiki.github.com/ciaranj/connect-auth/creating-a-form-basing-strargety

Tôi đang sử dụng express [ http://expressjs.com ] vì vậy plugin kết nối rất phù hợp vì express được phân lớp (ok - nguyên mẫu) từ kết nối


1
này, bạn có một ví dụ về những gì bạn đã làm không? chỉ cần yêu cầu kết nối-auth và gọi điện thoại.
Misha Reyzlin

1
IMHO Plugin này rất nặng nề để xác thực http đơn giản
Matthias

Và plugin này hoạt động chống lại kiến ​​trúc vòng kết nối hành tây
Matthias

14

Tôi đã cơ bản tìm kiếm điều tương tự. Cụ thể, tôi muốn như sau:

  1. Để sử dụng express.js, bao bọc khả năng phần mềm trung gian của Connect
  2. Xác thực "dựa trên mẫu"
  3. Kiểm soát chi tiết về các tuyến đường được xác thực
  4. Một cơ sở dữ liệu phụ trợ cho người dùng / mật khẩu
  5. Sử dụng phiên

Điều cuối cùng tôi làm là tạo ra chức năng phần mềm trung gian của riêng mình check_authmà tôi chuyển qua làm đối số cho mỗi tuyến tôi muốn xác thực. check_authchỉ kiểm tra phiên và nếu người dùng chưa đăng nhập, sau đó chuyển hướng họ đến trang đăng nhập, như vậy:

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

Sau đó, đối với mỗi tuyến, tôi đảm bảo chức năng này được truyền dưới dạng phần mềm trung gian. Ví dụ:

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

Cuối cùng, chúng ta cần thực sự xử lý quá trình đăng nhập. Điều này rất đơn giản:

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("/");
    }
  });
});

Ở mức độ nào, phương pháp này hầu hết được thiết kế linh hoạt và đơn giản. Tôi chắc chắn có nhiều cách để cải thiện nó. Nếu bạn có bất kỳ, tôi rất thích phản hồi của bạn.

EDIT: Đây là một ví dụ đơn giản. Trong một hệ thống sản xuất, bạn sẽ không bao giờ muốn lưu trữ và so sánh mật khẩu trong văn bản thuần túy. Như một bình luận chỉ ra, có những lib có thể giúp quản lý bảo mật mật khẩu.


2
Điều này là tốt, ngoại trừ bạn nên sử dụng bcrypt để lưu trữ mật khẩu (không phải văn bản thuần túy trong db). Có một bài tốt ở đây về nó: devsmash.com/blog/...
chovy


7

Đây là một số mã để xác thực cơ bản từ một trong các dự án của tôi. Tôi sử dụng nó để chống lại CouchDB và bộ đệm dữ liệu xác thực bổ sung, nhưng tôi đã loại bỏ mã đó.

Bao bọc một phương thức xác thực xung quanh bạn yêu cầu xử lý và cung cấp một cuộc gọi lại thứ hai để xác thực không thành công. Cuộc gọi lại thành công sẽ lấy tên người dùng làm tham số bổ sung. Đừng quên xử lý chính xác các yêu cầu có thông tin sai hoặc thiếu trong cuộc gọi lại thất bại:

/**
 * 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;
    }

};

Tôi muốn tránh auth cơ bản có lợi cho auth dựa trên mẫu. Đây chắc chắn là một giải pháp tao nhã cho vấn đề auth cơ bản. Tôi nghĩ rằng tôi có thể đã tìm thấy một khung xác thực tốt mặc dù (kết nối-auth - nằm trên đỉnh của kết nối)
shreddd

4

Một cách khác để xác thực là Passwordless, một mô-đun xác thực dựa trên mã thông báo để thể hiện vấn đề cố hữu của mật khẩu [1]. Việc triển khai nhanh, không yêu cầu quá nhiều hình thức và cung cấp bảo mật tốt hơn cho người dùng trung bình (công bố đầy đủ: Tôi là tác giả).

[1]: Mật khẩu đã lỗi thời


3

Một vài năm đã trôi qua và tôi muốn giới thiệu giải pháp xác thực của mình cho Express. Nó được gọi là Lockit . Bạn có thể tìm thấy dự án trên GitHub và một đoạn giới thiệu ngắn tại blog của tôi .

Vì vậy, sự khác biệt cho các giải pháp hiện có là gì?

  • dễ sử dụng: thiết lập DB của bạn, NPM cài đặt, require('lockit'), lockit(app), thực hiện
  • các tuyến đường đã được tích hợp sẵn (/ đăng ký, / đăng nhập, / quên mật khẩu, v.v.)
  • chế độ xem đã được tích hợp sẵn (dựa trên Bootstrap nhưng bạn có thể dễ dàng sử dụng chế độ xem của riêng mình)
  • nó hỗ trợ giao tiếp JSON cho các ứng dụng trang đơn AngularJS / Ember.js của bạn
  • nó KHÔNG hỗ trợ OAuth và OpenID. Chỉ usernamepassword.
  • nó hoạt động với một số cơ sở dữ liệu (CouchDB, MongoDB, SQL).
  • nó có các bài kiểm tra (tôi không thể tìm thấy bất kỳ bài kiểm tra nào cho Drywall)
  • nó được duy trì tích cực (so với everyauth)
  • xác minh email và quá trình quên mật khẩu (gửi email bằng mã thông báo, không được hộ chiếu hỗ trợ)
  • mô-đun: chỉ sử dụng những gì bạn cần
  • linh hoạt: tùy chỉnh tất cả mọi thứ

Hãy xem các ví dụ .


2

Có một dự án tên là Drywall thực hiện hệ thống đăng nhập người dùng bằng Passport và cũng có bảng quản trị quản lý người dùng. Nếu bạn đang tìm kiếm một hệ thống quản lý và xác thực người dùng đầy đủ tính năng tương tự như những gì Django có nhưng với Node.js, thì đây chính là nó. Tôi thấy đó là một điểm khởi đầu thực sự tốt để xây dựng một ứng dụng nút yêu cầu hệ thống quản lý và xác thực người dùng. Xem câu trả lời của Jared Hanson để biết thông tin về cách thức hoạt động của Hộ chiếu.



1

Ví dụ đơn giản nhanh bằng cách sử dụng mongo, cho API cung cấp xác thực người dùng cho máy khách Angular

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

cho tuyến đường của bạn một cái gì đó như thế này:

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

Sau đó, trong các tuyến đường yêu cầu xác thực, bạn chỉ có thể kiểm tra phiên người dùng:

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

0

Dưới đây là thư viện xác thực mới sử dụng mã thông báo được đánh dấu thời gian. Các mã thông báo có thể được gửi qua email hoặc nhắn tin cho người dùng mà không cần lưu trữ chúng trong cơ sở dữ liệu. Nó có thể được sử dụng để xác thực mật khẩu hoặc xác thực hai yếu tố.

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

Tiết lộ: Tôi là nhà phát triển của thư viện này.


0

Nếu bạn cần xác thực bằng SSO (Đăng nhập một lần) bằng tài khoản người dùng Microsoft Windows. Bạn có thể thử https://github.com/jlguenego/node-expose-sspi .

Nó sẽ cung cấp cho bạn một req.ssođối tượng chứa tất cả thông tin người dùng của khách hàng (đăng nhập, tên hiển thị, sid, nhóm).

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

Tuyên bố miễn trừ trách nhiệm: Tôi là tác giả của nút-expose-sspi.


0

ngọt ngào

Một mô-đun xác thực người dùng nhẹ, cấu hình không. Nó không cần một cơ sở dữ liệu vừa phải.

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

Nó đơn giản như:

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
    }
})
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.