+128

Bài toán phân quyền vấn đề muôn thuở.

(* Trong bài viết này mình chỉ nêu quan điểm và những thứ mình đã từng làm với việc phân quyền trên thực tế, chỉ mang tính tham khảo cho mọi người. Nếu có bất kỳ ý kiến góp ý nào hãy bình luận ở dưới để chúng ta cùng thảo luận thêm.)

Phân quyền công việc mang đầy tính năng nề đối với dev nhưng lại đầy sáng tạo cho người dùng. Như bạn biết khi phần mềm được dựng lên là có vô vàn rắc rối xoay quanh quyền hạn người sử dụng. Vì thế lập trình viên đã tạo ra một thứ mang tên phân quyền để tránh tình trạng mọi người đều là vua trong chương trình đó đơn giản với việc "Bạn được quyền làm việc đó hay không?".

1. Phân quyền là gì?

Tưởng tượng đơn giản như này nhé.

  • Bạn là sếp bạn có toàn quyền với nhân viên của mình
  • Bạn là trưởng phòng bạn chỉ có quyền với nhân viên trong phòng của mình
  • Bạn là trưởng nhóm dự án bạn chỉ có quyền với các thành viên trong nhóm
  • Và Nhóm < Phòng < công ty.
  • Như vậy bạn có thể thấy trong công ty này có 3 loại quyền hạn và chúng ta cần phân quyền theo nó

2. Bạn thường dùng loại phân quyền như thế nào?

  • Câu hỏi này mình đặt ra ban đầu là "Có các loại phân quyền nào?" nhưng thật sự việc phân quyền này rất ít được public do nó mang tính chất riêng tư của những dự án. Nên nếu bạn search thì chủ yếu sẽ chỉ tìm được cách tạo tài khoản sử dụng cho user trong các HQTCSDL.
  • Ở bài viết này mình sẽ nói về việc phân quyền bằng nhóm quyền (Group) Và đưa ra 1 số cách dựng CSDL (db).

3. Phân quyền theo group là gì và làm như thế nào ?

  • Phân quyền theo group là cách gọi chung của mình cho việc bạn nhóm nhiều thành viên trong 1 tổ chức có cùng một quyền hạn thực thi công việc. Lúc đó ta có thể nhóm họ vào 1 group để dễ dàng trao quyền hạn.
  • Như vậy từ cách phân quyền theo group này ta có thể sử dụng với "3 nấc" khác nhau.

Ví dụ đơn giản về 3 cách này nhé 😄

1. Phân quyền theo cấp bậc

  • Loại hình này chúng ta thường thiết kế db đơn giản như sau

  • Khi đó dữ liệu bạn dùng sẽ có dạng như thế này.

  • role ở đây là 1, 2, 3 tức là có 3 mức quyền hạn và lớn nhất hay bé nhất còn tùy thuộc vào quy định của mỗi công ty. Ví dụ

- Ưu điểm

Việc sử dụng kiểu phân quyền này dễ dàng cho những người mới bắt đầu. Những nhóm quyền được lập lên nhanh chóng có thể sử dụng luôn, Và việc phải check cũng tương đối là đơn giản, bạn chỉ cần 1 cần

select count(*) from tbl_... where id = ? and role = ?
hoặc
select role from tbl_... where id = ?

Rất dễ dàng để sử dụng đúng không. 😄

- Nhược điểm

Bạn biết đó việc sử dụng dữ liệu như này tồn tại 1 số nhược điểm rất lớn sau

  • Rất khó có thể mở rộng dự án
  • Trong thực tế không phải lúc nào cũng có 3 role. Nó có thể phát sinh nhiều role kì dị. Ví dụ: Thư ký giám đốc ngoài quyền đuổi việc ra còn lại nó sẽ có quyền của giám đốc vậy trường hợp này thuộc role 1 hay 2 ?.
  • Rất khó để phân quyền chi tiết.

2. Phân quyền theo chức năng

Loại phân quyền này được sử dụng rất nhiều trong thực tế. Nó rất hiệu quả và dễ thao tác đối với người cấp quyền.

Ta thiết kế db đơn giản trong ví dụ này như sau: Nhưng để Demo mình sẽ tóm gọn 2 bảng tbl_actiontbl_per_action thành bảng tbl_per_detail để dễ thao tác. Và ta có một Database như sau.

Chi tiết của việc thiết kế DB như sau:

  • tbl_user: bảng lưu người dùng bao gồm các thuộc tính như ID, Name,.... Bảng không có khóa ngoại.
  • tbl_permision: bảng chứa nhóm quyền hạn. bao gồm các thuộc tính, ID nhóm quyền hạn, tên nhóm quyền hạn.
  • tbl_permision_detail: là bảng sẽ chứa những quyền hạn cụ thể dành cho nhóm quyền hạn. Trường action_name không cần thiết bạn có thể bỏ. Trường action_code là để khi lập trình mình định nghĩa một thao tác nhất định trong bằng code này ví dụ quyền sửa thì code nó là EDIT chẳng hạn.
  • tbl_per_relationship: là bảng lưu mối liên hệ giữa người dùng và nhóm quyền hạn. Mục đích của bảng này không phải là để một người dùng có nhiều nhóm quyền mà để không phải truy vấn lại bảng user chứa thông tin nhạy cảm như username và password. Bạn cũng có thể bỏ qua bảng này và liên hệ trực tiếp giữa bảng user và permision luôn, nhưng mình khuyên bạn nên sử dụng thêm bảng này vì có nhiều trường hợp user có nhiều quyền hạn.

1. Kiểm tra dữ liệu trong các bảng

  • tbl_user

  • tbl_permision

  • tbl_per_detail

  • tbl_user_per

2. Làm một số ví dụ

  • Kiểm tra quyền của người dùng ví dụ: Hãy kiểm tra quyền của user có id là 1:
DECLARE @result NVARCHAR(1000)
SET @result = N'Những quyền hiện tại của user ('

select @result = @result + name_user + ') là: ' from tbl_user where id_user = 1
select @result = @result + action_name + ', ' from tbl_user as u
	join tbl_user_per as up on u.id_user = up.id_user
	join tbl_permision as p on up.id_per = p.id_per
	join tbl_per_detail as pd on p.id_per = pd.id_per
	where u.id_user = 1 and up.licensed = 1 and pd.check_action = 1
select @result = substring(@result, 0, len(@result))

print @result
  • kết quả

  • Kiểm tra xem user 2 có quyền xóa bài viết không ?
DECLARE @result bit
select @result = check_action from tbl_user as u
	join tbl_user_per as up on u.id_user = up.id_user
	join tbl_permision as p on up.id_per = p.id_per
	join tbl_per_detail as pd on p.id_per = pd.id_per
	where u.id_user = 2 and up.licensed = 1 and action_code = 'DELETE'

begin
	if @result = 1
		print N'Bạn CÓ quyền xóa post'
	else
		print N'Bạn KHÔNG có quyền xóa post'
end
  • kết quả

  • Đó là một số ví dụ đơn giản tron tình huống này khi sử dụng phân quyền theo nhóm (group)

3. Kết luận

- Ưu điểm
  • Việc phân quyền này như mình có nêu ngay từ ban đầu rất dễ thao tác đối với những admin khi họ muốn chuyển nhóm quyền hoặc thỏa sức sáng tạo trong việc tạo ra những quyền mới từ những quyền ban đầu. Ví dụ như người dùng vừa có thể EDITDELETE,....
  • Ngoài ra việc thực hiện những câu querry cũng rất dễ dàng cho những lập trình viên.
- Nhược điểm
  • Vấn đề sử dụng quyền hành động rất dễ khi chúng ta làm việc trên 1 group, nhưng nếu trong chương trình của bạn có nhiều group và phân cấp nhiều tầng thì nó lại là một vấn đề nan giải khác, khi bạn không chỉ phải check quyền hành động mà bạn còn phải check xem quyền hành động này của người dùng có thể áp dùng được trong group khác hay không?..

3. Phân quyền theo Hành động của các nhóm Group theo những cấp bậc khác nhau

  • Đây là loại phân quyền lằng ngằng nhất nhưng lại là quan trọng nhất, bởi các lý do sau đây:
  • Các tổ chức sử dụng phần mềm để thực hiện thao tác của họ đều có phân cấp rõ ràng
  • Trong những tổ chức có những người nắm full quyền của nhiều nhóm
  • Có những thành viên thuộc nhiều nhóm
  • Có những thành viên tuy chỉ là nhân viên nhưng lại có quyền của các sếp (thư ký)
  • Chính vì có nhiều trường hợp như vậy những lập trình viên sinh ra được rất nhiều case trong code.

Giải quyết vấn đề này bạn có thể tìm hiểu cách thự hiện phân quyền trong odoo.

  • Phân quyền theo model: Có nghĩ là người dùng được thao tác thực hiện với những bảng dữ liệu nào

Ví dụ: Admin có thể thực hiện với thao tác với bảng user của họ

  • phân quyền theo raw: Người dùng được thực hiện việc thao tác với các raw được chỉ định

Ví dụ: Leader A chỉ có thể thực hiện thao tác với những thành viên của mình trong bảng user

  • phân quyền theo column: Người dùng sẽ được quyền thao tac với nhưng column đó

Ví dụ: Chỉ giám đốc mới có thể đuổi việc nhân viên, ở đây ta sẽ có 1 column tên là is_working để biết việc nhân viên đó còn đi làm hay không 😄

4. Kết luận

  • Việc bạn sử dụng cách nào hay thứ tự ra sao tưởng rằng không quan trọng nhưng nếu nhìn xa hơn trong việc mở rộng cũng như update phần mềm thì đó có thể là cực hình cho người sau.
  • Nếu bạn được quyền tham gia vào thiết kế database (thường là review và góp ý) thì hãy xem xét đến các vấn đề về việc những trường hợp phát sinh đề phòng những người tạo ra DB thiếu sót.

Loại phân quyền thứ 3 có rất nhiều kiểu biến hóa trong từng phần mềm của từng công ty, Và mình sẽ cố gắng tìm hiểu thêm để viết một bài nói về kiểu này ngoài ra mình cũng sẽ cố gắng viết 1 bài nói về kiểu phân quyền của odoo. Thực chất nó cũng gần giống kiểu phân quyền trong group thôi 😄. Cảm ơn các bạn đã đọc bài viết của mình. Văn phong hơi lủng củng nên mong các bạn thông cảm!.


All rights reserved

Bình luận

Đăng nhập để bình luận
Avatar
@chungminhtu
thg 5 16, 2018 9:24 SA

Bài viết rất hay và chi tiết. Cung cấp nhiều hình ảnh minh họa dễ hiểu. Keep up the good work!

Avatar
@tuanbacyen
thg 5 16, 2018 9:26 SA

Vâng em cảm ơn ạ. 😃 E đang cố gắng viết mấy bài cơ bản để giúp bạn yếu SQL để dễ làm việc hơn. Giống như những gì mà mình đã từng được những người khác giúp ạ 😄.

Avatar
@chungminhtu
thg 5 16, 2018 9:28 SA

Uhm bài viết của em hay là vì mang tính thực tiễn cao. Chứng tỏ em từng nghiên cứu kỹ để đưa vào áp dụng cho dự án thật. Những bài viết như thế này rất có giá trị tham khảo cho người mới và cả người cũ.

Avatar
@tuanbacyen
thg 5 16, 2018 9:29 SA

Em ăn hành nhiều nên cũng có biết cách chế biến hành để người sau làm việc hiệu quả hơn anh ạ 😄.

Avatar

Cảm ơn ạ... Bài viết rất thiết thực...

Avatar
@tuanbacyen
thg 5 16, 2018 9:46 SA

Cảm ơn bạn đã đọc bài của mình 😄 😄

Avatar
@phumaster.dev
thg 5 17, 2018 2:29 SA

Thanks bác. Cái cuối có ví dụ nữa thì tốt ạ 👍👍

Avatar
@tuanbacyen
thg 5 17, 2018 2:43 SA

Cái cuối mình sẽ viết trong bài sau. vì nó không có tổng quát cụ thể mà do từng dự án mọi người làm nên nó nhiều loại lắm 😄. Thank bạn nha!.

Avatar
@phumaster.dev
thg 5 17, 2018 2:51 SA

Vâng 😄

Avatar
@duongnguyen1216
thg 5 17, 2018 3:18 SA

hay thật, rất dễ hiểu, cảm ơn Anh Tuấn

Avatar
@tuanbacyen
thg 5 17, 2018 3:21 SA

Cảm ơn bạn nhes1 😄.

Avatar

Bài viết của bạn rất hay và dễ hiểu 😄

Avatar
@tvad911
thg 5 17, 2018 6:23 SA

Cái thứ 3 thì có 1 packet có xài như sau: https://github.com/signes-pl/laravel-acl

Có vài điểm cảm thấy ko đúng như luồng suy nghĩ thông thường, nhưng xài thì vẫn tốt, cơ mà chưa kiếm được dự án đủ tầm để áp dụng.

Avatar
@tuanbacyen
thg 5 17, 2018 6:53 SA

Theo mình nếu làm theo cách của này thì có vài chỗ sẽ bị quanh quẩn như kiểu bảng user vs group, user vs role. Dẫn đến sẽ khó hiểu cho những người mới đọc vì luồng dữ liệu không clear khi đọc lần đầu. Nếu mình làm thì mình sẽ đưa người dùng ra 1 phía vì bài toán phục vụ cho họ nên phần phân quyền ta tự quyết định với nhau xong cần 1 bảng user-role là được. Tất nhiên cách của bạn đưa ra họ đã tính đến vài trường hợp mà mình chưa gặp nên chắc họ làm vòng như thế là có lý do. Nếu bạn muốn chi tiết hơn có thể xem cách phân quyền của joomla nó cũng làm giống kiểu này nè 😄 Cảm ơn bạn đã bình luận và góp ý cho mình. 😄

Avatar
@tuyenvv92
thg 5 17, 2018 11:30 CH

Bài viết rất hay, cảm ơn bạn.

Mình đang có bài toán trên hệ thống của mình như sau và chưa biết nên xây dựng theo kiểu nào thì hợp lý. Đã có vài cách rồi nhưng vẫn chưa đc hợp lý lắm.

  1. Phân quyền theo group,

Ví dụ

  • Role Giám đốc có thể xem thông tin toàn bộ nhân viên
  • Role Trưởng phòng xem thông tin toàn bộ nhân viên cấp dưới trưởng phòng
  • Role Trưởng nhóm xem thông tin toàn bộ nhân viên caaso dưới của trưởng nhóm nhóm
  • => Chỉ được xem thông tin của mình và toàn bộ nhân viên cấp dưới
  1. Phân quyền theo Module hệ thống

Role hoặc cá nhân 1 người nào đó có thể Xem, Sửa, Xóa hoặc Export trên 1 module nào đó, trên 1 field nào đó của module đó

Ví dụ Trưởng phòng được xem thông tin của nhân viên cấp dưới mình, và chỉ được xem không được sửa.

Trưởng nhóm chỉ được xem thông tin nhân viên cấp dưới mình và không được xem field "Lương" của module đó.

Hiện tại mình đang tách ra riêng thành 2 hệ thống phân quyền.

1 là quản lý theo role

2 là module và field

Bạn có thể cho ý kiến được không nhỉ.

Avatar
@tuanbacyen
thg 5 18, 2018 1:22 SA

Bạn có thể xem thêm về cách phân quyền ở git của bạn trên cung cấp cho chúng ta tham khảo: https://github.com/signes-pl/laravel-acl

Còn theo ý kiến cá nhân của mình bạn có thể gộp 2 loại này vào 1 bảng để check. Nhưng nếu bạn bạn đã làm quản lý theo 2 loại quyền tách biệt đó rồi thì mình thấy bạn nên viết 1 hàm để sử lý trường hợp này. tránh việc khi gom thành 1 bảng sẽ bị trồng quyền bằng cách tạo 1 function kiểu như này:

def check_logic user_child, action
  if user_child is member of self.user
   check_action action, self.user.role   (check true/false)
  end
  return false
end

def check_action action, role
  select ... from tbl_... where action = '+ 'action' +' and role = '+role+'
end

Vì nếu bạn để khi gộp lại quyền thì khổ nhất là công đoạn check quyền bạn sẽ phải sử dụng nhiều join và sub querry. Từ đó request sẽ lâu hơn khổ hơn khi sinh ra quyền mới. Nên mình thấy bạn phân ra làm 2 loại check là hợp lý. Nhưng hợp nếu đc hãy tạo thêm 1 table trung gian và có nhiều quyền trong đó hơn. khi đó user chỉ cần tạo quan hệ với bảng đó.

Nếu tính ra tbl_permission_grop có m row

tbl_permission_action có n row

=> bản chung gian chỉ cao nhất là m*n row.

Còn bảng chung gian giữa user và tbl_group_permission_action thì có tối thiểu m*n row. Và chỉ cần 3 join là lấy được quyền.

select ... from tbl_user 
   join tbl_group_permission_action
   join tbl_permission_grop
   join tbl_permission_action
   where action = ... and user = ...

Đó là quan điểm của mình trên những gì bạn đã làm. Nếu bạn đã làm gần ra sản phẩm thì nên cho nó debut trước. sau đó sẽ thấy nhiều vấn đề lúc này đập đi làm lại hẵng hay. 😃

Avatar
@tuyenvv92
thg 5 24, 2018 9:29 SA

Thanks bạn, hóng bài tiếp theo

Avatar
@duc2820
thg 5 18, 2018 2:47 SA

bài viết rất hay ạ. mong tác giả viết thêm nhiều bài về design database là một trong những chỗ mà mình thấy ngứa nhất (thực ra là mình thấy khó) : (((

Avatar
@tuanbacyen
thg 5 18, 2018 3:00 SA

Cảm ơn bạn mình đang cố gắng viết nhiều bài như này để giúp cho mọi người nhiều hơn nữa 😄

Avatar
@nyn548
thg 5 18, 2018 5:06 SA

Bài viết rất hay. Mô tả tốt các cách phân quyền thường dùng.

Avatar
@tuanbacyen
thg 5 18, 2018 5:47 SA

Cảm ơn bạn nhé 😄

Avatar

Cảm ơn b rất nhiều. Mong là ra nhiều bài viết liên quan đến Database như này, hay hơn nữa là về phân quyền trong các hệ thống lớn.

Avatar
@quangnam98
thg 11 13, 2018 7:08 CH

yupp..cám ơn anh vì bài viết này. Thật sự vô cùng bổ ích, đúng vấn đề em đang mắc phải. Cám ơn anh và chúc anh thành công trong cuộc sống !

Avatar
@vanthanh090785
thg 9 29, 2019 2:44 SA

Bài Tập

  1. Tạo các users John, Joe, Fred, Lynn, Amy, and Beth: a. Password là tên username. b. Đảm bảo các user này có thể tạo bất kỳ bảng nào trong tablespace với quota 10M.

  2. Cho bảng Attendance ( ID INT PRIMARY KEY, Name NVARCHAR2 ) Làm các bước sau: a. Tạo các role sau: DataEntry, Supervisor, và Management. b. Gán John, Joe, và Lynn vào role DataEntry, gán Fred vào role Supervisor, và gán Amy và Beth vào role Management. c. Cho role DataEntry các quyền SELECT, INSERT, và UPDATE trên bảng Attendance. d. Cho role Supervisor các quyền SELECT và DELETE trên bảng Attendance. e. Cho role Management quyền SELECT trên bảng Attendance. f. Lần lượt kiểm tra kết quả phân quyền đã cấp cho các role

  3. Thực hiện các yêu cầu sau đối với các view được liệt kê ở phần II (Từ điển dữ liệu): a. Tìm quyền mà trong tên của quyền có chữ CONTEXT b. Liệt kê tất cả user có quyền SELECT ANY TABLE

  4. Thực hiện các bước sau: a. Gán password cho role DataEntry ở bài 1 là “mgt” b. Cho phép user John quyền cấp quyền cho các user khác

ai giup minh giai bai nay voi

Avatar
@sylitas
thg 12 15, 2020 4:44 SA

bài viết quá tốt cho bản thân mình nói riêng

Avatar

cho mình hỏi trường hợp action trên nhiều bảng thì mình phải thêm action tương ứng, vd: user có EDIT_USER, UPDATE_USER, DELETE_USER, READ_USER, và mỗi bảng sẽ thêm 4 action đó phải không ạ

Avatar
@dev032422
thg 8 25, 2022 8:57 SA

tks

Avatar
@trandong1248
thg 8 12, 2023 3:47 SA

Tuấn em đại học mỏ k59 à. Kaka Chịu khó viết bài nhỉ 😃)

Avatar
@tach-gai
thg 5 10, 2024 7:13 SA

tbl_per_relationship: là bảng lưu mối liên hệ giữa người dùng và nhóm quyền hạn. Mục đích của bảng này không phải là để một người dùng có nhiều nhóm quyền mà để không phải truy vấn lại bảng user chứa thông tin nhạy cảm như username và password. Bạn cũng có thể bỏ qua bảng này và liên hệ trực tiếp giữa bảng user và permision luôn, nhưng mình khuyên bạn nên sử dụng thêm bảng này vì có nhiều trường hợp user có nhiều quyền hạn.

=> tbl_per_relationship có diễn giải nhưng ko có hình ảnh & dữ liệu tbl_per_relationship

Avatar
+128
Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí