Chat Application - Authentication

9/18/2021 NodeJsExpressJsSocketIo

# Authentication:

Sử dụng passport và jwt để xử lí authentication cho app.

# 1.Install:
$ npm i passport passport-jwt passport-local jsonwebtoken
1
# 2.Passport authenticate middleware:
  • Register:

    Callback handle:

    ​Nếu model User đã define pre-hook tự động mã hóa password khi save thì không cần set password = await bcrypt.hash(password, 10); thủ công nữa.

    ​Define các file usernameField, passwordField passport sẽ tự động get giá trị các field trong request body và đưa vào callback các giá trị tương ứng.

// File: auth/auth.js

const passport = require('passport'); const localStrategy = require('passport-local').Strategy; const User = require('../models/user'); const JWTStrategy = require('passport-jwt').Strategy; const ExtractJWT = require('passport-jwt').ExtractJwt; const bcrypt = require('bcrypt');

passport.use( 'register', new localStrategy( { usernameField: 'name', passwordField: 'password' }, async (name, password, done) => { try { password = await bcrypt.hash(password, 10); const user = await User.create({name, password});

    return done(null, user);
  } catch (error) {
    done(error);
  }
}

) );


  Sử dụng middleware tại router:

  ```js
  // File: routes/auth.js
  
  router.post(
    '/register',
    [
      upload.single('avatar'),
      passport.authenticate('register', {session: false})
    ],
    async (req, res, next) => {
      if (req.user) {
        const user = req.user;
        if (req.file) {
          user.addAvatar('assets/images/' + req.file.filename);
        }
        return res.json({
          message: 'Register successful',
          status: true
        });
      }
      return res.json({
        message: 'Register fail',
        status: false
      });
    }
  );
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

Sử dụng 2 middleware:

  • upload avatar: sử dụng multer

  • passport authenticate register đã define ở trên.

  • Login:

    Callback handle: Tương tự register, login xử lí find và verify user.

    passport.use(
      'login',
      new localStrategy(
        {
          usernameField: 'name',
          passwordField: 'password'
        },
        async (name, password, done) => {
          try {
            const user = await User.findOne({name});
    
            if (!user) {
              return done(null, false, {message: 'User not found'});
            }
    
            const validate = await user.verifyPassword(password);
    
            if (!validate) {
              return done(null, false, {message: 'Password in correct'});
            }
    
            return done(null, user, {message: 'Logged in Successfully'});
          } catch (error) {
            return done(error);
          }
        }
      )
    );
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28

    Sử dụng middleware tại router:

    router.post(
      '/login',
      async (req, res, next) => {
        passport.authenticate(
          'login',
          async (err, user, info) => {
            try {
              if (err) {
                return next(err);
              }
              if (!user) {
                const error = new Error(info.message);
                error.status = 401;
                return next(error);
              }
    
              req.login(
                user,
                {session: false},
                async (error) => {
                  if (error) return next(error);
    
                  const body = {_id: user._id, name: user.name};
                  const token = jwt.sign({user: body}, 'TOKEN_SECRET');
    
                  return res.json({token, name: user.name, avatar: user.avatar, _id: user._id});
                }
              );
            } catch (error) {
              return next(error);
            }
          }
        )(req, res, next);
      }
    );
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35

    Trường hợp login thành công return token về client và các request sau sẽ kèm theo token này để verify user.

  • JWT middleware:

    Verify token của user get được từ login

    passport.use(
      new JWTStrategy(
        {
          secretOrKey: 'TOKEN_SECRET',
          jwtFromRequest: ExtractJWT.fromUrlQueryParameter('token')
        },
        async (token, done) => {
          try {
            return done(null, token.user);
          } catch (error) {
            done(error);
          }
        }
      )
    );
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15

    Get token trong request query param token, nếu get trong headers bearer thì dùng methodfromAuthHeaderAsBearerToken (note: nếu dùng bearer token thì authenticate cho socket hiện bị lỗi chưa resolved được). {session: false}: passport sẽ verify bằng token không dùng session.

    // File: app.js
    app.use('/user', passport.authenticate('jwt', {session: false}), userRoute);
    
    // File: routes/user.js
    router.get(
      '/profile',
      (req, res, next) => {
        res.json({
          status: true,
          user: req.user,
        })
      }
    );
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
  • Socket authentication: detail ở phần sau.


Series:

Github: https://github.com/ninhnguyen22/chat_app (opens new window)