Chức năng đăng nhập đăng kí gần như ứng dụng nào cũng có ,trong đó bảo mật thông tin , xác thực người dùng vẫn luôn là vấn đề thiết yếu , vậy sau đây hãy cùng tôi sử dụng JWT , Bcrypt để làm Authentication xác thực cho ứng dụng NodeJS nhé
Authentication và Authorization
Mình sẽ có một bài viết riêng về 2 khái niệm này và so sánh chúng , theo dõi để cập nhật sớm nhất nhé ^^
Trước hết hãy cùng nhắc lại JWT là gì
JWT là một cơ chế bảo mật để 2 phía client và server có thể chia sẻ thông tin với nhau . Các thông tin trong một chuỗi JWT được lưu dưới dạng JSON . Trong đó chuỗi được chia làm 3 phần là header , payload , signature được ngăn cách bởi dấu "."
Một ví dụ về JWT
Mã hóa
const jwt = require('jsonwebtoken');
var token = jwt.sign({
userId: userData._id
}, 'secretKey' , { expiresIn: 15 * 60 * 1000})
Đối số đầu tiên truyền vào có thể là string hoặc object , mình sử dụng object vì trong thực tế cần mã hóa nhiều thông tin của người dùng hơn là chỉ mỗi id .
secretKey là một đoạn string bất kỳ mà bạn phải giữ bảo mật về nó , không nên để lộ . expiresIn là thời gian sống của token này , đơn vị là ms , ở đây mình đặt exprire time là 15 phút
Kết quả
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbiI6IjYyMDA4ZGM1YWQ1ZjM4MzkzNDhiYjkzOSIsImlhdCI6MTY0NDIwNTE4NywiZXhwIjoxNjQ0MjA4Nzg3fQ.OwnkztlOIcowHPGyVkfFAzvo1rzWis43JOt6WhSQUUg
JWT sẽ dùng để làm gì trong ứng dụng này ?
Đối với Authorization , sau khi đăng nhập , ta có token token hay accessToken để xác định được người dùng và quyền truy cập của họ . Ta sẽ sử dụng JWT để mã hóa và trao đổi giữa sever với client . Thường thì chuỗi được mã hóa sẽ là object chứa id của user được lưu trong DB , và một số dữ liệu cần thiết .
Vậy còn Bcrypt là cái chi ?
Bcrypt là một thuật toán mã hóa mật khẩu được thiết kế bởi Niels Provos and David Mazières.
Tại sao ứng dụng của mình cần Bcrypt ?
Sử dụng Bcrypt cho Authentication , mã hóa mật khẩu của người dùng
Trong nodejs , node module Bcrypt rất dễ để cài đặt và sử dụng cùng với đó là tính bảo mật cao . Mỗi lần mã hóa lại cho ra một kết quả khác nhau vì vậy rất khó để dò được mật khẩu .
Ví dụ sử dụng bcrypt
var passwordHash = await bcrypt.hash(userdata.password , 10)
// Lưu passwordHash vào DB
Đối số đầu tiên là password của người dùng khi đăng ký tài khoản , đối số thứ 2 là saltRound . Hãy dùng await để trong trường hợp hash tốn thời gian thì vẫn ra được kết quả trong DB nhé .
Kết quả
$2b$10$ljxxJLlduwm5r.mMycMWhO2kg9tqCD/FxbHYzWAwk3O.oyNo0zScS
Mình sẽ demo services và routes của chức năng đăng kí và đăng nhập nhé , full code server mình sẽ để dưới cùng để các bạn tham khảo
/services/accounts
const Account = require('../models/Account');
const bcrypt = require('bcrypt')
async function getUser(userdata) {
const data = await Account.findOne({
user: userdata.user,
});
const match = await bcrypt.compare(userdata.password, data.password);
//hàm so sánh password user nhập vào với password mã hóa trong DB
if(match){
return data
}else{
return null
}
}
async function createUser(userdata) {
var passwordHash = await bcrypt.hash(userdata.password , 10)
const newUSer = await new Account({
user: userdata.user,
password: passwordHash,
});
return newUSer.save()
}
module.exports = {
getUser: getUser,
createUser: createUser,
};
/routes/signup
const express = require('express');
const router = express.Router();
const accountServices = require('../services/account');
const jwt = require('jsonwebtoken');
router.get('/', (req,res,next)=>{
res.render('signup');
})
router.post('/',async (req,res,next)=>{
try {
const userData = await accountServices.createUser(req.body);
res.status(200).json({
statusCode: 200,
mess: 'Signup success'
}
} catch (error) {
res.status(500).json({
statusCode: 500,
mess: 'Sever error'
})
}
});
module.exports = router;
/routes/login
const express = require('express');
const router = express.Router();
const accountServices = require('../services/account');
const jwt = require('jsonwebtoken');
router.get('/', (req,res,next)=>{
res.render('login');
})
router.post('/',async (req,res,next)=>{
try {
const userData = await accountServices.getUser(req.body);
if(!userData){
res.status(400).json({
statusCode: 400,
mess : 'User or password was wrong'
})
}else{
res.status(200).json({
statusCode: 200,
mess: 'Login success',
token : jwt.sign({token: userData._id},'id',{expiresIn: '1h'})
})
}
} catch (error) {
res.status(500).json({
statusCode: 500,
mess: 'Sever error'
})
}
});
module.exports = router;
Full code server : https://github.com/nsutgkhanhv1/basic-authen
Tham khảo thêm tại :
https://www.npmjs.com/package/bcrypt
https://www.npmjs.com/package/jsonwebtoken