Hướng dẫn authentication reactjs nodejs - xác thực reactjs nodejs

Hôm nay chúng ta sẽ tiếp tục serie Node JS + React JS với chủ đề là authentication + authorization

Hôm nay chúng ta cùng đi tìm hiểu hai khái niệm cơ bản là Authentication và Authorization, cũng như tìm hiểu về cách implement nó trong ứng dụng NodeJS sẽ như thế nào nhé (go)

Giới thiệu

Bài viết sẽ tập trung vào phía backend với các follow basic nhất như đăng ký, đăng nhập, cách trả về token cho client ...

Ở chức năng này thì chúng ta cần viết các api sau:

  • API register account
  • API get user detail
  • API sign in
  • Middleware authentication
  • Authorization when get list todos

Authentication

Authentication chỉ việc xác thực người dùng, định danh được một người dùng trong hệ thống thông qua đăng nhập, việc định danh có thể thông qua email, user name, số điện thoại ... độc nhất và đại diện cho người dùng đó trong hệ thống.

Authentication tóm tắt cho câu hỏi: Who are you?Who are you?Who are you?

Authorization

Authorization thì là bước xác định người dùng đó có quyền gì trong hệ thống, sau khi user Authentication thành công, người đó sẽ có quyền truy cập những tài nguyên nào chính là chỉ việc Authorization.

Còn Authorization tóm tắt cho câu hỏi : What are you allowed to do?What are you allowed to do?What are you allowed to do?

Bắt đầu thôi ! Follow cơ bản sẽ là:

  • Người dùng đăng ký tài khoản
  • Người dùng đăng nhập, server trả về token
  • Client sử dụng token này để authentication + authorization

Register

Chúng ta sẽ implement api đơn giản với việc đăng ký bằng email + password

Ở model user, chúng ta cần một hàm static để hash password mà user set, sử dụng Bcrypt để hash pasword nhé mọi người.

// models/user.js
const bcrypt = require('bcrypt');
const saltRounds = 10;

class User extends Model {
  static generatePasswordHash(query, cb) {
    let password = query.password.toString();
    return bcrypt.hash(password, saltRounds);
  }
}

Ở controller UserController, chúng ta cần viết hàm để đăng ký tài khoản cũng như hàm để lấy thông tin user

Đầu tiên là hàm register, ở hàm này chúng ta lấy thông tin email + password để tạo account, đồng thời cấp token cho client. Client sẽ cần lưu lại token này ở browser, sử dụng nó gắn vào mỗi request headers khi gọi api.

class UserController {
  static async register(req, res, next) {
    let {email, password} = req.body;
    let userJson = {
      email: email,
      password: password
    }
    let hash = await User.generatePasswordHash(userJson);
    if (hash) {
      var user = await User.create({email: email, passwordHash: hash});
      if (!_.isNil(user)) resHelper(res, 200, {token: user.generateJWTToken(), user: user.jsonData(), message: 'Create user success'}, 'Create user success');
    } else {
      resHelper(res, 400, {message: 'Create user failed'}, 'Create user failed');
    }
  }
}

Hàm generateJWTToken() chúng ta trả về token chứa gì trong đó ?

  • Lưu ý : JWT token không được chứa dữ liệu nhạy cảm, như chứa token khác hay là password cũng như thông tin bí mật. Bởi vì JWT token payload thực chất là một chuỗi base64 có thể decode dễ dàng. : JWT token không được chứa dữ liệu nhạy cảm, như chứa token khác hay là password cũng như thông tin bí mật. Bởi vì JWT token payload thực chất là một chuỗi base64 có thể decode dễ dàng. : JWT token không được chứa dữ liệu nhạy cảm, như chứa token khác hay là password cũng như thông tin bí mật. Bởi vì JWT token payload thực chất là một chuỗi base64 có thể decode dễ dàng.

Mọi người có thể tìm hiểu thêm về Jwt ở đây nhé https://jwt.io/introduction , https://viblo.asia/p/tim-hieu-ve-json-web-token-jwt-7rVRqp73v4bP

Ở đây mình sẽ dùng package jsonwebtoken để sign payload chứa email và userId, để khi decode token chúng ta có thể định danh được user nào đang request lên hệ thống.

var jwt = require('jsonwebtoken');

class User extends Model {
  generateJWTToken() {
    return jwt.sign({email: this.email, userId: this._id}, process.env.JWT_SECRET);
  }
}

Login

Với login thì chúng ta cần kiểm tra email và password mà user truyền lên. Nếu hợp lệ thì trả về token còn không sẽ bắn lỗi.

const _ = require('lodash');

class AuthController {
  static async sign_in(req, res, next) {
    var {email, password} = req.body;
    if (_.isNil(email) || _.isNil(password)) return resHelper(res, 400, {}, 'Invalid parameter');
    var user = await User.get({email: email});
    if (_.isNil(user)) return resHelper(res, 404, null, 'Not found');
    var isAuth = await user.verifyPassword(password);
    if (isAuth) {
      var token = user.generateJWTToken();
      return resHelper(res, 200, {token: token}, 'Sign in success');
    } else {
      return resHelper(res, 400, {error: 'Invalid usename or password'}, 'Sign in failed');
    }
  }
}

Authentication

Authentication chỉ việc xác thực người dùng, định danh được một người dùng trong hệ thống thông qua đăng nhập, việc định danh có thể thông qua email, user name, số điện thoại ... độc nhất và đại diện cho người dùng đó trong hệ thống.

Authentication tóm tắt cho câu hỏi: Who are you?Who are you?

Authorization

  static async authenticate_user (req, res, next) {
    var authHeader = req.headers['authorizationtoken'];
    if (authHeader && authHeader.split(' ')[0] !== 'Bearer') resHelper(res, 401, {error: 'Unauthorized'}, 'Unauthorized');
    if (_.isNil(authHeader)) return resHelper(res, 401, {error: 'Unauthorized'}, 'Unauthorized');
    var token = authHeader.split(' ')[1];
    var decodedToken = null;
    try {
      decodedToken = jwt.verify(token, process.env.JWT_SECRET);
      var currentUser = await User.get({name: decodedToken.userName});
      if (_.isNil(currentUser)) return resHelper(res, 400, {error: 'bad request'}, 'Bad request');
      res.locals.currentUser = currentUser;
    } catch (error) {
      return resHelper(res, 400, {error: 'bad request'}, 'Bad request');
    }
    if (_.isNil(decodedToken)) return resHelper(res, 400, {error: 'bad request'}, 'Bad request');
    next();
  }

Authorization

Authorization thì là bước xác định người dùng đó có quyền gì trong hệ thống, sau khi user Authentication thành công, người đó sẽ có quyền truy cập những tài nguyên nào chính là chỉ việc Authorization.

  static user (req, res, next) {
    try {
      resHelper(res, 200, {user: res.locals.currentUser.jsonData()}, 'Load user success');
    } catch {
      resHelper(res, 400, {}, "Bad request");
    }
  }

Còn Authorization tóm tắt cho câu hỏi : What are you allowed to do?What are you allowed to do?

Bắt đầu thôi ! Follow cơ bản sẽ là:

// config/api.routes.js

var AuthMiddleware = require('../middlewares/auth_middleware.js');
var AuthController = require('../controllers/api/auth_controller.js');

module.exports = function(router) {
  ...
  router.get('/auth/user', AuthMiddleware.authenticate_user, AuthController.user);
  ...
}

Người dùng đăng ký tài khoản

Người dùng đăng nhập, server trả về token

Client sử dụng token này để authentication + authorization

Register

Chúng ta sẽ implement api đơn giản với việc đăng ký bằng email + password

Ở model user, chúng ta cần một hàm static để hash password mà user set, sử dụng Bcrypt để hash pasword nhé mọi người.

  • Ở controller UserController, chúng ta cần viết hàm để đăng ký tài khoản cũng như hàm để lấy thông tin user
  • Đầu tiên là hàm register, ở hàm này chúng ta lấy thông tin email + password để tạo account, đồng thời cấp token cho client. Client sẽ cần lưu lại token này ở browser, sử dụng nó gắn vào mỗi request headers khi gọi api.