Sử dụng Casbin để phân quyền cho người dùng trong hệ thống

Sử dụng Casbin để phân quyền cho người dùng trong hệ thống

Những mẩu tin ngắn hàng ngày dành cho bạn
  • Tin tức sáng sớm, mọi người còn nhớ vụ kiện của Ryan Dahl - hay nói đúng hơn là của nhóm Deno với Oracle về cái tên JavaScript không?

    Oracle đã phản hồi rằng họ không từ bỏ cái tên JavaScript đâu 🫣

    https://x.com/deno_land/status/1876728474666217739

    » Xem thêm
  • Mọi người nghỉ tết sớm rồi hay sao á? Nhiên cái nguyên tuần nay traffic giảm hẳn luôn 😳. Một mình tuôi nói kể cũng buồn, ai đi ngang qua đọc được thì thả một "còm men" cho vui cửa vui nhà nha. Nói gì cũng được vì ẩn danh cả mà 😇🔥

    » Xem thêm
  • Có người hỏi mình là cập nhật tin tức ở đâu mà nhanh thế, hay là kiếm ra được mấy cái tools, mấy cái projects... ở đâu mà nhiều thế? Thì có một nguồn xa tận chân trời mà gần ngay trước mắt đó chính là trang Github Trending này đây.

    Trang này thống kê lại các kho lưu trữ đang có lượt "star" nhiều nhất theo ngày/tuần/tháng. Nó còn xem theo được ngôn ngữ cơ, mà mỗi ngôn ngữ lại kiểu như một chủ đề á. Ví dụ Python thì hót rần rần về AI, LLMs..., Rust thì bao tools siêu mạnh, còn Go thì... đồ chơi liên tục 😁. Trong khi JavaScript 🫣😑

    » Xem thêm

Vấn đề

Phân quyền là một tính năng xuất hiện ở rất nhiều nơi trong ứng dụng phần mềm. Đơn cử như việc chia sẻ tệp tin trên internet cho nhau, bạn có thể cho người nhận quyền đọc, tải về hoặc chỉnh sửa nội dung... Còn trong các ứng dụng quản lý hệ thống như CMS, phân quyền trở nên cần thiết hơn bao giờ hết. Mỗi người dùng chỉ nên có quyền truy cập vào tài nguyên được phép để tránh gặp phải những rắc rối sau này.

Trước đây khi làm phân quyền, cách đơn giản nhất là sử dụng if...else để kiểm tra một thuộc tính nào đó, ví dụ như là role của người dùng có hợp lệ khi thao tác với tài nguyên. Ví dụ, người dùng có roleadmin sẽ có quyền tối cao trong hệ thống, trong khi mod thì có quyền thấp hơn. Hai hàm checkAdmincheckMod được tạo ra để kiểm tra nhanh xem người dùng có đang là admin hay là mod, chúng được gọi khi cần kiểm tra quyền trước khi đụng đến logic xử lý tài nguyên.

function checkAdmin(role) {
    if (role === "admin") {
		return true;
    }
	return false;
}

function checkMod(role) {
    if (role === "mod") {
		return true;
    }
	return false;
}

Đó chỉ phù hợp cho các ứng dụng đơn giản mà không đòi hỏi phân quyền nghiêm ngặt. Thực tế thì đôi khi ứng dụng của chúng ta cần quản lý chặt chẽ hơn, ví dụ như một nhóm người dùng là mod có quyền đọc/ghi vào dữ liệu ở các API nhất định. Đôi khi chúng ta còn phải xây dựng một trang quản lý quyền của người dùng, đó mà một màn hình chi chít thiết lập dành cho người dùng, hành động và cả tài nguyên được phép truy cập.

Tôi tin rằng có rất nhiều cách để triển khai phân quyền và nó đi theo từng trường hợp cụ thể của mỗi hệ thống. Vì thế bài toán bảo trì mới cần được bàn đến. Nếu như việc triển khai phân quyền từ đầu không tốt hoặc gây khó khăn trong đọc hiểu, mở rộng thì cần mất nhiều thời gian hơn nếu muốn sửa đổi, nâng cấp. Ngược lại, khi chúng ta có một tiếng nói chung thì khả năng tiếp cận vấn đề lại nhanh hơn đáng kể.

Casbin là một thư viện kiểm soát truy cập mã nguồn mở, nó cung cấp khả năng hỗ trợ cho việc thực thi ủy quyền dựa trên các mô hình kiểm soát truy cập khác nhau. Các mô hình phân quyền phổ biến được Casbin hỗ trợ và triển khai trong nhiều ngôn ngữ lập trình khác nhau. Nói cách khác, nó chỉ đơn giản hóa việc viết mã của bạn cho vấn đề phân quyền.

Các loại kiểm soát quyền truy cập

Có khá nhiều cách để kiểm soát quyền truy cập, chưa kể đến sự tùy biến của chúng để phù hợp cho nhiều bài toán của mỗi ứng dụng. Nhưng nhìn chung, chúng ta có 3 cách phổ biến là ACL, RBAC và ABAC.

ACL là viết tắt của cụm từ Access Control List, nghĩa là người dùng được ánh xạ tới các hành động đối với tài nguyên.

Trước khi tiếp tục, có 3 khái niệm cơ bản để kiểm soát quyền truy cập đó là người dùng - hay nói một cách bao quát là đối tượng (sub), chúng ta có tài nguyên cần truy cập (obj) và hành động mà đối tượng được phép với tài nguyên (act).

Quay trở lại với ví dụ đầu tiên, mod có quyền thêm/sửa/xóa bài viết. Bài viết lúc này là obj, hành động thêm/sửa/xóa là act và mod chính là sub. Đây là một ví dụ điển hình cho ACL.

Phức tạp hơn một chút, chúng ta có RBAC là viết tắt của Role-Based Access Control - Kiểm soát truy cập dựa trên vai trò.

RBAC cũng khá giống ACL ở các quyền và tài nguyên được phép truy cập, nhưng thay vì gán quyền trực tiếp đến một đối tượng người dùng cuối thì nó tạo ra một đối tượng trung gian gọi là "role", người dùng có "role" nào thì sẽ có quyền của role đó.

Ví dụ mod có quyền thêm/sửa/xóa bài viết, hoaitx là một người dùng trong hệ thống và có "role" là mod cho nên hoaitx có quyền thêm/sửa/xóa bài viết...

Một mô hình phổ biến nữa là kiểm soát truy cập dựa trên thuộc tính ABAC - Attribute-Based Access Control. ABAC cũng khá tương đồng với RBAC, nhưng thay vì quản lý quyền theo "role" thì ABAC quản lý quyền theo thuộc tính (attribute). Nghĩa là đối tượng có mang thuộc tính nào thì sẽ có quyền của thuộc tính đó. Một ví dụ cho dễ liên tưởng là gắn tags, nếu người dùng hoaitx được gắn tags read_article và nó có quyền đọc bài viết thì hoaitx cũng có quyền đọc bài viết...

Triển khai trong thực tế

Trước khi triển khai, chúng ta hãy dành thời gian để tìm hiểu cách hoạt động của Casbin, vì một khi đã hiểu thì có thể giúp bạn làm quen nhanh hơn với mô hình phân quyền này.

Trong Casbin, mô hình kiểm soát truy cập được trừu tượng hóa thành tệp CONF dựa trên siêu mô hình PERM. Mô hình PERM bao gồm bốn nền tảng: Policy, Effect, Request, và Matchers. Những nền tảng này mô tả mối quan hệ giữa tài nguyên và người dùng.

Để tìm hiểu chi tiết về 4 nền tảng này, bạn đọc tham khảo thêm tại How It Works - Casbin.

Các tệp CONF định nghĩa cho mô hình phân quyền ACL, RBAC, ABAC... bạn có thể tự tạo cho mình một cấu hình riêng hoặc sử dụng các mẫu có sẵn của Casbin. Ví dụ một tệp sử dụng cho ACL có dạng như sau:

# Request definition
[request_definition]
r = sub, obj, act

# Policy definition
[policy_definition]
p = sub, obj, act

# Policy effect
[policy_effect]
e = some(where (p.eft == allow))

# Matchers
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act

Tiếp đến chúng ta cần một tệp định nghĩa các giá trị sub, obj, act... như đã nêu đầu bài viết, mục đích là chỉ định cho đối tượng có quyền gì với tài nguyên nào. Các tệp này được gọi là tệp policy.

Ví dụ policy của một ACL như sau:

p, hoaitx, article, read
p, hoaitx, article, write

Sau đó sử dụng 2 tệp tin này trong mã để kiểm tra điều kiện phân quyền. Ví dụ khi triển khai với Node.js, đầu tiên cài đặt modules casbin:

$ npm i casbin

Sau đó sử dụng:

import { newEnforcer } from 'casbin';

const e = await newEnforcer('path/to/model.conf', 'path/to/policy.csv');

Với path/to/model.conf là đường dẫn đến tệp CONF, path/to/policy.csv là đường dẫn đến tệp policy vừa tạo ra.

Sau đó để kiểm tra người dùng hoaitx có quyền read tài nguyên article hay không rất đơn giản:

const sub = 'hoaitx';
const obj = 'article';
const act = 'read';

if ((await e.enforce(sub, obj, act)) === true) {
    // permit
} else {
    // deny
}

Đó chỉ là ví dụ cơ bản, Casbin cung cấp rất nhiều mô hình phân quyền nâng cao hơn nữa, các API mạnh mẽ khác như quản lý policy một cách linh hoạt hoặc hỗ trợ lưu trữ, cập nhật các tệp CONF theo nhiều cách khác nhau. Bạn đọc tìm hiểu thêm tại API OverviewModel Storage hoặc bắt đầu với trang tài liệu chính thức của Casbin: Overview.

Cao cấp
Hello

5 bài học sâu sắc

Mỗi sản phẩm đi kèm với những câu chuyện. Thành công của người khác là nguồn cảm hứng cho nhiều người theo sau. 5 bài học rút ra được đã thay đổi con người tôi mãi mãi. Còn bạn? Hãy bấm vào ngay!

Mỗi sản phẩm đi kèm với những câu chuyện. Thành công của người khác là nguồn cảm hứng cho nhiều người theo sau. 5 bài học rút ra được đã thay đổi con người tôi mãi mãi. Còn bạn? Hãy bấm vào ngay!

Xem tất cả

Đăng ký nhận thông báo bài viết mới

hoặc
* Bản tin tổng hợp được gửi mỗi 1-2 tuần, huỷ bất cứ lúc nào.

Bình luận (0)

Nội dung bình luận...
Bấm hoặc cuộn mạnh để sang bài mới