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
  • Hẳn là nhiều người ở đây đã nghe đến kiểu tấn công bảo mật Clickjacking rồi nhỉ. Kẻ tấn công thường nhúng một website (thường là mục tiêu) vào trong một iframe trên website của chúng, sau đó làm mờ hoặc ẩn nó đi rồi đặt vào vị trí các nút bấm trên web, ví dụ "Bấm vào để nhận quà". Đâu ai ngờ rằng phía trên nút bấm đó là một nút bấm khác trong iframe. Khá nguy hiểm!

    Nhưng trình duyệt đã có cách ngăn chặn kiểu tấn công này bằng các quy tắc như tiêu đề X-Frame-Options, frame-ancestors của CSP và SameSite: Lax/Strict của Cookies...

    Mới đây, đã xuất hiện thêm kiểu tấn công mới - "DoubleClickjacking" 😨. Đại ý là "hắn" lợi dụng hành động double click để lừa người dùng bấm vào một nút mà hắn muốn. Chi tiết hơn trong bài viết này: DoubleClickjacking: A New Era of UI Redressing.

    » Xem thêm
  • Mọi người đã nghe nói đến Jujutsu - jj - một dạng quản lý phiên bản cho mã nguồn (version control system) chưa? Có vẻ như nó đang nhận được nhiều sự quan tâm.

    Chờ xíu! Chẳng phải git đã quá tốt rồi sao? Thế thì chế ra thằng jj để làm gì nữa? Cũng hơi khó trả lời nhỉ? Mỗi công cụ sinh ra chắc chắn phải cải thiện hoặc khắc phục được nhược điểm của cái trước. Cho nên jj ắt hẳn phải làm được điều gì đó mà git chưa làm được nên mới nổi lên như vậy.

    Thật ra mình đã nghe nói đến jj từ vài tháng trước rồi, nhưng vào đọc thì toàn kiến thức cao siêu. Hoặc là đang mang nặng cái lối suy nghĩ của git vào trong đầu rồi nên chưa lĩnh hội ra được điều gì cả.

    Mình hay có kiểu cái gì đọc lần 1 mà không hiểu thì đọc tiếp lần 2, lần 2 không hiểu thì đọc tiếp lần 3... đến lần thứ n mà vẫn không hiểu thì bỏ. Cơ mà không phải là từ bỏ mà một thời gian sau đó quay lại đọc tiếp. Đến một lúc nào đó khả năng mình sẽ hiểu ra một ít vấn đề, thế mới tài 😆.

    Thì cái jj này có vẻ như nó đang mở ra được tính linh hoạt trong việc "cam kết" mã. Tưởng tượng bạn đang làm việc trên một dự án, đang ở nhánh này, muốn sang nhánh khác để sửa, nhưng mà lại đang viết dở ở nhánh này, thế là phải stash, rồi checkout, rồi commit, rồi merge hoặc rebase lại vào nhánh cũ... nhìn chung quá trình làm việc với git nghiêm ngặt đến mức cứng nhắc, cần nhiều thao tác để giải quyết một vấn đề, chưa kể cái cây commit (commit-tree) nữa thì ôi thôi, khỏi xem cho đỡ nhức mắt. Thế nên ông jj này đang làm cách nào đó để bạn khỏi cần phải quan tâm đến các nhánh luôn, sửa trực tiếp vào commit. Nghe ảo nhỉ 😂.

    Đấy mới lĩnh hội được đến đấy, hy vọng sau n lần đọc lại nữa mình sẽ viết được một bài chi tiết hơn về công cụ này.

    » Xem thêm
  • Gòi gòi tới công chiện gòi 🤤🤤🤤

    » 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