Bài viết


Sử dụng middleware để bảo vệ route và phân quyền trong Firebase

Ngày đăng: 01/07/2024

Khi làm việc với API chúng ta sẽ luôn thường xuyên phải xác thực người dùng để sử dụng từng API và cấp từng quyền riêng cho mỗi user như admin, quản lý, khách hàng, ... Để làm được điều đó ta sẽ dùng middleware, xem như đoạn mã trung gian kết nối giữa request và response, nó sẽ check xem user đó đã đăng nhập chưa và có quyền được dùng API đó hay không, nếu thông qua được thì API sẽ trả về dữ liệu, còn ngược lại sẽ trả về lỗi.


Trong bài này ta sẽ sử dụng middleware để xác thực và phân quyền API trong Firebase.


1. Middleware xác thực route


Đầu tiên, tạo file firebase.js.


const admin = require('firebase-admin');
const serviceAccount = require('./serviceAccountKey.json');


admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: `https://${serviceAccount.project_id}.firebaseio.com`,
});


const db = admin.firestore();


module.exports = {admin, db};


Trong đó, file serviceAccountKey.json chứa thông tin ADMIN SDK khi tạo 1 app trên firebase


Tiếp theo, tạo 1 cloud function thực hiện chức năng get tất cả user. File getUser.js


module.exports.getAllUsers = async (req, res) => {
try {
// get tất cả user ở đây
} catch (error) {
return res.status(500).json(error.message);
}
};


Tiếp đó, tạo middleware để xác thực request


const { admin, db } = require("../config/firebase");


const isAuthenticated = async (req, res, next) => {
const tokenInHeader = req.header("Authorization");


if (!tokenInHeader) {
res.status(401).send({
code: 401,
message: "Chưa xác thực!"
});
}


try {
const authUser = await admin.auth().verifyIdToken(tokenInHeader)
const entry = db.collection('user').doc(authUser.uid)
const user = (await entry.get()).data() || {};

res.locals = { ...res.locals, role: user.role }
return next();
} catch (err) {
console.log(err, 'error')
res.status(401).json(err.messsage);
}
}


module.exports = { isAuthenticated }


Khi xác thực xong, ta lưu biến role vào res.locals để dùng cho middleware phân quyền phía dưới.


Tạo file route


const express = require("express");
const api = express();
const cors = require("cors");

api.use(cors());

const { getAllUsers } = require("../controllers/user/getUser");


api.get('/', [isAuthenticated], getAllUsers);


Trong route truyền middleware xác thực user phía trên vào, nếu token được truyền lên hợp lệ thì api sẽ trả về danh sách tất cả user, ngược lại sẽ trả về lỗi.


Cuối cùng, ở client khi thực hiện gọi api, ta truyền token lên trong header


headers = {
'Authorization': token
};


Trong đó, biến token chính là token khi user thực hiện xác thực với chức năng Authentication của firebase


2. Phân quyền trong firebase


File middleware phân quyền


const isAuthorized = (opts) => {
return (req, res, next) => {
const { role } = res.locals || {}

if (!role)
return res.status(403).send();


if (opts.hasRole.includes(role))
return next();


return res.status(403).send();
}
}


module.exports = {isAuthorized}


Cũng trong file route trên, truyền thêm vào middleware phân quyền


const express = require("express");
const api = express();
const cors = require("cors");

api.use(cors());

const { getAllUsers } = require("../controllers/user/getUser");


api.get('/', [isAuthenticated, isAuthorized({ hasRole: ['ADMIN'] })], getAllUsers);


Lúc này, user phải được xác thực và có quyền là ADMIN thì mới được sử dụng API này. Các bạn muốn thêm middleware nào nữa thì chỉ cần truyền vào array như trên là được


Như vậy chúng ta đã nắm được 2 chức năng cơ bản khi làm việc với API là xác thực và phân quyền cho route. Điều này là quan trọng cho một ứng dụng web app được bảo mật tốt.


Liên hệ ngay tại đây với chúng tôi để được tư vấn nhanh nhất hoặc liên hệ:

Hotline: 0705.550.553

Email: bqsoftvn@gmail.com

Fanpage: https://www.facebook.com/bqsoftvn


Hân hạnh được hợp tác!

icon zalo
icon-mess