Vietnam

    Nodejs.vn

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Popular
    • Tags
    • Groups
    • Search

    Tìm hiểu về Passport.js: Các bước để xác thực tài khoản

    ExpressJS/Conect.IO
    expressjs node.js passportjs
    2
    15
    22232
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • Quốc Cường
      Quốc Cường last edited by Quốc Cường

      Passport.js một trong những module phổ biến nhất của Nodejs hỗ trợ bạn authentication . Nó được thiết kế là một middleware hết sức linh hoạt cho bạn khả năng tùy biến cao với rất nhiều các kịch bản authentication: bạn có thể sử dụng Twitter, Facebook, Google thậm chí là qua username-password trong database. Bạn cũng có thể tùy biến chính xác các route nào cần phải authentication .
      Trong bài viết chúng ta sẽ đi tìm hiểu sâu về cơ chế hoạt động của thằng Passport nhé, bài này giúp bạn tự tin trong việc custom lại nó 😃

      Thiết lập Passport cho ứng dụng

      Trước khi đâu sâu vào bên trong, ta hãy ngõ qua cách đề cài đặt passport cho ứng dụng đã. Để sử dụng được passport bạn có tối thiểu 3 bước :

      Require thằng passport và chèn 2 thằng middile của nó vào express là passport.initialize() và passport.session(). Chú ý là ứng dụng express của bạn cần sử dụng đến express-session.

      var app = require('express')();
      var session = require('express-session');
      var bodyParser = require('body-parser');
      var passport = require('passport');
      
      app.use(bodyParser.json());
      app.use(bodyParser.urlencoded({ extended: false }));
      
      app.use(session({
        secret : "secret",
        saveUninitialized: true,
        resave: true
      }))
      
      app.use(passport.initialize());
      app.use(passport.session());
      
      app.listen(3333);
      

      Cấu hình 1 kịch bản cho thằng Passport và thiết lập 2 hàm serializeUser , deserializeUser

      var LocalStrategy = require('passport-local').Strategy;
      var passport = require('passport');
      var bcrypt = require('bcrypt');
      
      passport.serializeUser(function(user, done) {
          done(null, user.id);
      });
      
      passport.deserializeUser(function(id, done) {
          db.user.findById(id).then(function (user) {
              done(null, user);
          }).catch(function (err) {
              console.log(err);
          })
      });
      
      passport.use(new LocalStrategy(
          function (username,password,done) {
              db.user.find({where : {
                  username : username
              }}).then(function (user) {
                  bcrypt.compare(password, user.password, function (err,result) {
                      if (err) { return done(err); }
                      if(!result) {
                          return done(null, false, { message: 'Incorrect username and password' });
                      }
                      return done(null, user);
                  })
              }).catch(function (err) {
                  return done(err);
              })
          }
      ))
      

      Thiết lập 1 route có dùng middleware passport.authenticate.

      router.route('/login')
          .get(function (req, res) {
              res.render('login', {
                  'title': 'Log in'
              })
          })
          post('/login', passport.authenticate('local', { successRedirect: '/',
                                                                                        failureRedirect: '/login' }));
      

      Các bước xác thực tài khoản qua request của người dùng.

      Ví dụ bạn đặt route xác thực tài khoản là /login. Khi người dùng đăng nhập vào vệ thống passport sẽ xử lý như sau:

      1. Khi người dùng submit form đăng nhập, một request POST được tạo ra tới route /login , nó sẽ chạy cái middleware passport.authenticate cho bạn.Như trên ta thiết lập kịch bản Local cho thằng passport.authenticate nên nó sẽ gọi đến cái kịch bản ta đã cài đặt.

      2. Nó lấy dữ liệu req.body.username và req.body.passport rồi gán cho hàm verify local.
        Ở đây như cấu hình ở trên ta thấy chúng ta sẽ query database rồi kiểm tra xem passport của người dùng đưa lên có đúng không.Trong trường hợp Error từ db ta gọi đến callback là done với param là err( done(err)) Khi mà nó không tìm thấy được người dùng hợp lý ta gọi đến thằng done(null,false). Còn nếu thông tin đăng nhập đúng ta gọi done(null,user).Khi callback done được gọi, nó sẽ lấy dữ liệu err, user và dữ liệu bạn custom thêm nếu có trả lại cho thằng passport.authenticate.

      3. Nếu dữ liệu trả về của callback là null, true, xác thực thành công passport tiếp tục gọi hàm req.login( cái này tự gắn vào từng request khi bạn cài đặt passport ở bước 1)

      4. Hàm req.login gọi đến thằng passport.serializeUser mà ta đã định nghĩa trước đó. Hàm này truy cập vào đối tượng user mà ta trả về cho middleware passport.authenticate và xác định xem thành phần nào của đối tượng sẽ lưu vào trong session. Kết quả của hàm này là ta sẽ có đối tượng req.session.passport.user = các thông tin ta truyền vào trong serializeUser.Trong ví dụ bên trên thì nó là user.id. Đồng thời với trên passport cũng có gắn thông tin user vào req.user.

      5. Việc xác thực kết thục, hàm requestHandler sẽ được gọi đưa chúng tra đến trang đã thiết lập
        Xác thực các request sau khi đăng nhập.

      Tất nhiên chúng ta chỉ đăng nhập 1 lần vào hệ thống, không phải cứ làm bất cữ việc gì ta cũng phải điền username - password. Trong các request tiếp theo đến hệ thống passport hoạt động như sau:

      1. Với mỗi request , express sẽ load các sữ liệu trong session ra và gắn nó và đối tượng request (req.session). Ở trên ta đã sử dụng hàm serializeUser để đưa dữ liệu vào session nên ta có thể tìm thấy dữ liệu đó tạo req.session.passport.user.
      2. Middleware khởi động passport (passport.initialize) sẽ check xem trong request session có passport.user không. Nếu chưa có là chưa xác thực thì thằng req.session.passport.user = {}
      3. Tiếp đó passport.session được gọi. Nếu thấy passport.user trong sesion request đó được tính là đã xác thực.
      4. Khi request được tính là đã xác thực nó sẽ gọi hàm passport.deserializeUser. Hàm này sử dụng thông tin trong session để lấy dữ liệu đầy đủ về thằng user rồi gắn nó vào req.user.
        Tổng kết

      Ở đây mình tóm tắt lại các hàm các middleware của passport :

      • passport.initialize : middleware được gọi ở từng request, kiểm tra session lấy ra passport.user nếu chưa có thì tạo rỗng.
      • passport.session: middleware sử dụng kịch bản Passport , sử dụng session lấy thông tin user rồi gắn vào req.user.
      • passport.deserializeUser : hàm được gọi bởi passport.session .Giúp ta lấy dữ liệu user dựa vào thông tin lưu trên session và gắn vào req.user
      • passport.authenticate: middleware giúp ta gắn kịch bản local vào route.
      • passport.serializeUser: hàm được gọi khi xác thực thành công để lưu thông tin user vào session
        Các hàm hỗ trợ thêm cho từng request

      Với từng request passport gắn thêm cho bạn 4 hàm :

      req.login()
      req.logout()
      req.isAuthenticated()
      req.isUnauthenticated()
      

      Tên chúng nói lên tất cả rồi phải không 😃
      bài viết lược dịch từ : http://toon.io/understanding-passportjs-authentication-flow/
      nguồn bài viết : http://techmaster.vn/posts/33637/tim-hieu-ve-passportjs-cac-buoc-de-xac-thuc-tai-khoan

      1 Reply Last reply Reply Quote 0
      • K
        kxd993 last edited by

        A cho e hỏi là với một express app route cùng một url , sử dụng cùng rest api thì có cách nào để xác thực được route sẽ sử dụng thông qua role của người dùng không ???

        Giả sử trong đoạn code sau , e muốn user sau khi được authen qua passport . Nếu user có role là "user" thì sẽ vào route1 còn user có role là "admin" thì sẽ vào route2.

        var express = require('express');
        var app = express();
        // route for user
        app.route('/users').get(function(req , res , next) {
        res.send('route1');
        });
        // route for admin
        app.route('/users).get(function(req , res , next) {
        res.send('route2');
        });
        app.listen(8080);

        Quốc Cường 1 Reply Last reply Reply Quote 0
        • Quốc Cường
          Quốc Cường @kxd993 last edited by

          @kxd993 ở đây thằng passport có hỗ trợ em 1 thằng req.user > em có thể lấy req.user.roles. Ta tạo 1 cái middleware
          function(req,res,next){
          next(req.user.roles)
          }

          ở hàm xử lý viết dạng function (role, req, res){ với từng role thì để logic riêng, tách các logic ra thành 2 hàm cũng được
          }
          Có rất nhiều cách để thực hiện đây là 1 cách theo anh nghĩ là khá dễ làm

          K 1 Reply Last reply Reply Quote 0
          • K
            kxd993 @Quốc Cường last edited by

            @Quốc-Cường Thanks a, do e xem nhầm code một chút vì với điều kiện là cùng route với cùng restAPI thì đúng là k thể chia role được như kiểu của e .

            1 Reply Last reply Reply Quote 0
            • N
              nvs2394 last edited by

              Anh cho em hỏi là em có login(vs angular ) và set session cho nó là 6 phút. Làm sao sau 6 phút bên client em chưa logout ra mà session này vẫn còn để em có thể lấy được req.user để gửi 1 post hay get khác.
              Thanks a. em viết hơi khó hiểu và dài

              Quốc Cường 1 Reply Last reply Reply Quote 0
              • Quốc Cường
                Quốc Cường @nvs2394 last edited by

                @nvs2394 đã nói trong Tìm hiểu về Passport.js: Các bước để xác thực tài khoản:

                Anh cho em hỏi là em có login(vs angular ) và set session cho nó là 6 phút. Làm sao sau 6 phút bên client em chưa logout ra mà session này vẫn còn để em có thể lấy được req.user để gửi 1 post hay get khác.
                Thanks a. em viết hơi khó hiểu và dài

                ực khó hiểu thật . Khi em thiết lập thời hạn cho cookie hoặc session thì tuỳ vào cơ chế của trình duyệt hoặc nó sẽ tự động xoá nó đi không thì nó sẽ không đính kèm khi gửi request lên trên server nữa và em không thể lấy được thông tin này.

                1 Reply Last reply Reply Quote 0
                • N
                  nvs2394 last edited by

                  Hiện giờ em làm như thế này :
                  Em dùng passport login cho web. xong nó lưu lại biến req.user để mỗi lần post get get em có thể lấy req.user._id . em có xét trong session là 6 phút. Bên client em GET hàm loggedin để lấy thông tin của user đã login và show ra. Giả sử khi em đang upload 1 tấm hình mà nó hết mất 6 phút thì session đó đã bị hết hạn nhưng người dùng vẫn chưa upload xong

                  Quốc Cường 1 Reply Last reply Reply Quote 0
                  • Quốc Cường
                    Quốc Cường @nvs2394 last edited by

                    @nvs2394 Sao em phải xét set session ngắn như vậy ?

                    1 Reply Last reply Reply Quote 0
                    • CodeConCat
                      CodeConCat last edited by

                      Theo ý kiến cá nhân của mình thì bạn có thể format lại bài viết này cho dễ xem hơn, nhìn vào thấy luôn một "wall-of-text", không hấp dẫn lắm cho một bài viết "có thể đã hay".

                      codeconcat

                      Quốc Cường 1 Reply Last reply Reply Quote 0
                      • Quốc Cường
                        Quốc Cường @CodeConCat last edited by

                        @CodeConCat đã nói trong Tìm hiểu về Passport.js: Các bước để xác thực tài khoản:

                        Theo ý kiến cá nhân của mình thì bạn có thể format lại bài viết này cho dễ xem hơn, nhìn vào thấy luôn một "wall-of-text", không hấp dẫn lắm cho một bài viết "có thể đã hay".

                        đã sửa lại bài này cũ lắm rồi

                        1 Reply Last reply Reply Quote 0
                        • T
                          Tuấn Phạm Hoàng last edited by

                          Cho e hỏi passport khi em dùng với nhiều fields thì nó ko làm việc vậy anh, a có thể giúp e ko ? ví dụ e có bảng account(id, fullname, email, password, phone...)

                          haidangdevhaui 1 Reply Last reply Reply Quote 0
                          • haidangdevhaui
                            haidangdevhaui @Tuấn Phạm Hoàng last edited by

                            @Tuấn-Phạm-Hoàng phải nhập cả đống field đấy mới cho đăng nhập à

                            tobi

                            T 1 Reply Last reply Reply Quote 0
                            • T
                              Tuấn Phạm Hoàng @haidangdevhaui last edited by

                              This post is deleted!
                              1 Reply Last reply Reply Quote 0
                              • Nhan Tam
                                Nhan Tam last edited by

                                Mình có ứng dụng chat tích hợp trên website, nhưng mỗi khi refresh bị mất session. Có bác nào biết cách khắc phục xin chỉ giúp.
                                Thanks các bác

                                Kha Pham 1 Reply Last reply Reply Quote 0
                                • Kha Pham
                                  Kha Pham @Nhan Tam last edited by Kha Pham

                                  @Nhan-Tam mình dùng thêm JWT để lưu ở localstore rồi gửi lên server check nếu đúng thì gán req.session.passport.user = id người dùng.
                                  F5 hoặc tắt server củng không vấn đề gì. lần sau vẫn đăng nhập được. Nhớ là mỗi khi phải gửi cái token đó lên mỗi khi f5 để nó check và gán

                                  Đam mê công nghệ
                                  Không biết nhiều nhưng cũng muốn đóng góp

                                  1 Reply Last reply Reply Quote 0
                                  • First post
                                    Last post
                                  $(document).ready(function () { app.coldLoad(); }); }