Bạn vẫn xem được toàn bộ bài học mà không cần đăng nhập.
Giấu menu không phải là phân quyền. Ba tầng trả lời ba câu khác nhau, và cái bẫy menu công khai làm cả phòng ban mất menu chỉ vì bạn gán thêm một nhóm.

Tuần đầu sau go-live, trưởng phòng kinh doanh nhắn một câu ngắn: nhân viên kho đang nhìn thấy giá bán.
Bạn kiểm lại thì phân quyền đã làm đúng yêu cầu, nhóm kho không có menu Bán hàng và không vào được danh sách đơn hàng. Nhưng phiếu xuất kho có một trường trỏ ngược về đơn bán hàng gốc, và bấm theo đường đó thì đơn mở ra đầy đủ, đơn giá và tổng tiền nằm ngay giữa màn hình.
Chuyện này không phải do ai cấu hình nhầm. Trên Odoo 19, ngay khi cài module sale_stock
Nghĩa là mặc định thì người kho vừa xem được vừa sửa được, và bạn phải chủ động thu hẹp lại nếu nghiệp vụ không cho phép, rồi chạy lại luồng giao hàng để chắc rằng việc thu hẹp không làm gãy thao tác của kho.
Sự cố này xảy ra vì phân quyền trong Odoo có ba tầng, và thứ mà phần lớn người mới thao tác nhiều nhất lại không phải một tầng bảo mật.
Toàn bộ phần cơ chế trong bài này tôi mô tả trên Odoo 19, và đây là loại nội dung bạn phải dựng lại trên đúng bản mình đang chạy chứ không nên tin theo trí nhớ.
Nắm khung trước, vì có khung rồi thì gặp yêu cầu phân quyền nào bạn cũng biết nó thuộc tầng nào.
Ba câu đó độc lập với nhau, và một yêu cầu từ khách hàng có thể rơi vào bất kỳ tầng nào.
Nhầm tầng thì bạn giải sai bài. Rất nhiều yêu cầu tầng ba bị xử lý bằng cách giấu cả menu, và kết quả là người dùng vừa không xem được thứ họ không nên xem, vừa không làm được thứ họ phải làm.
Hai khái niệm nền trước khi đi tiếp.
Tài liệu chính thức của Odoo 19 chia người dùng theo bốn vai trò.
Ràng buộc quan trọng nhất ở đây là trên màn hình người dùng, phần gán nhóm quyền theo phân hệ chỉ hiện ra với người dùng nội bộ. Nghĩa là mọi thứ bài này nói tới đều áp dụng cho nhân sự bên trong doanh nghiệp, còn phân quyền cho đối tác bên ngoài là một câu chuyện khác.
Về nhóm quyền thì vai trò kiến trúc của nó đáng hiểu chứ không chỉ đáng dùng. Nhóm quyền là lớp nằm giữa nối người dùng với dữ liệu, tức bạn khai báo một nhóm được làm gì rồi gán người vào nhóm, thay vì đi gán từng người với từng chức năng. Gán tay từng người từng chức năng thì chỉ cần dự án lớn lên một chút là bạn không còn kiểm soát nổi ai đang có quyền gì, và tới lúc khách hỏi thì phải dò lại từ đầu.
Nhóm quyền cũng kế thừa nhau, tức nhóm cấp cao có sẵn quyền của nhóm cấp thấp rồi thêm phần của mình. Đây là lý do trên màn hình người dùng, với nhiều phân hệ bạn chỉ chọn một cấp trong danh sách thả xuống, chẳng hạn chỉ tài liệu của mình, tất cả tài liệu hay quản trị, bởi các cấp đó là một chuỗi kế thừa.
Muốn biết một người thực sự đang có những nhóm nào thì bật chế độ nhà phát triển rồi mở tab Technical Access Rights trên hồ sơ của họ, nơi tách riêng nhóm được chọn và nhóm được thêm tự động do kế thừa.
Tầng này khai báo với mỗi đối tượng dữ liệu thì một nhóm được thực hiện những thao tác nào, và có bốn thao tác là Read, Write, Create và Delete.
Bốn quyền đó độc lập với nhau, nên cấp ba bỏ một là chuyện bình thường và trong nhiều trường hợp còn là chuyện nên làm. Chẳng hạn cho kế toán xem, sửa và tạo hóa đơn nhưng không cho xóa là một cấu hình rất hay dùng, bởi xóa là thao tác duy nhất trong bốn thao tác không có đường lùi, và một hóa đơn bị xóa nhầm thì kéo theo cả chuỗi đối chiếu phía sau.
Cần lưu ý thêm rằng quyền ở tầng này cộng dồn chứ không loại trừ nhau: một người thuộc nhiều nhóm thì quyền của họ là hợp của tất cả các nhóm đó. Nghĩa là ở tầng này, thêm một nhóm chỉ có thể mở rộng quyền chứ không bao giờ thu hẹp, và gán thêm một nhóm cho tiện chính là cách vô tình mở ra thứ bạn không định mở.
Có một mẹo tra cứu đáng nhớ khi bạn cần biết một đối tượng đang cấp quyền cho những nhóm nào. Bật chế độ nhà phát triển, mở màn hình của đối tượng đó, bấm vào biểu tượng con bọ, rồi xem mục Access Rights trong nhóm bảo mật; ở đó liệt kê đầy đủ nhóm nào đang được xem, sửa, tạo, xóa trên đối tượng này, và ngay bên dưới là mục Record Rules của tầng hai.
Khi khai báo một quyền mới thì có một chi tiết dễ sai ở phần chọn đối tượng. Sau khi Việt hóa, tên hiển thị của các đối tượng không còn giống tên trong hệ thống, và nhiều đối tượng có tên na ná nhau như đơn bán hàng với dòng đơn bán hàng, nên cách an toàn là tìm theo tên kỹ thuật, chẳng hạn sale.order.line, chứ đừng chọn theo tên tiếng Việt. Chọn nhầm thì quyền vẫn được tạo bình thường, chỉ là gắn vào sai đối tượng.
Đây là điểm quan trọng nhất của cả bài, và nó giải thích luôn câu chuyện ở đầu bài.
Menu và quyền truy cập là hai thứ tách rời, nên chúng giao nhau thành bốn trường hợp.
Có menu | Có quyền | Kết quả |
|---|---|---|
Có | Có | Dùng bình thường |
Không | Có | Vẫn mở được bằng đường link hoặc bằng trường liên kết ở màn hình khác |
Có | Không | Menu mở danh sách bản ghi thường bị hệ thống tự ẩn; menu nào vẫn hiện thì bấm vào sẽ báo lỗi |
Không | Không | Không truy cập được |
Trường hợp thứ hai là lỗ hổng, và nó phổ biến hơn nhiều người nghĩ. Người dùng không thấy menu nên bạn tưởng họ không vào được, trong khi chỉ cần một đồng nghiệp gửi đường link qua tin nhắn, hoặc một màn hình khác mà họ có quyền có sẵn một trường hay một nút dẫn sang, là họ mở được đúng thứ bạn nghĩ đã giấu đi. Câu chuyện phiếu xuất kho ở đầu bài chính là trường hợp này.
Do đó nguyên tắc phải nhớ rất gọn: giấu menu là chuyện giao diện cho gọn, không phải chuyện bảo mật. Muốn chặn thật thì chặn ở tầng quyền truy cập.
Trường hợp thứ ba thì ngược lại, không phải lỗ hổng mà là phiền toái, và trên Odoo 19 nó hiếm hơn nhiều người nghĩ. Hệ thống tự kiểm quyền đọc trên đối tượng mà menu sẽ mở ra, và thiếu quyền đó thì menu bị ẩn đi kể cả khi người dùng thuộc đúng nhóm được gán cho menu.
Phần còn lại là những menu mở màn hình đặc biệt hoặc cần tới đối tượng khác mà người dùng không có quyền, và khi đó họ bấm vào rồi nhận thông báo lỗi. Về mặt bảo mật thì không sao, nhưng đây là chuyện khiến khách hàng gọi cho bạn, nên vẫn nên dọn.
Đây là cái bẫy mà ai làm phân quyền Odoo cũng nên biết trước khi chạm vào màn hình cấu hình.
Một menu chưa được gán cho nhóm quyền nào thì hệ thống xét hiển thị theo quyền đọc trên đối tượng mà menu mở ra, tức ai đọc được đối tượng đó thì thấy menu. Nghe thì hợp lý, và phần lớn menu con trong hệ thống ở trạng thái đó.
Vấn đề xảy ra khi bạn cần cho một nhóm thấy menu đó và bạn làm việc hiển nhiên nhất là gán menu cho nhóm ấy. Ngay khi bạn lưu, hành vi của menu đổi hẳn: từ chỗ ai có quyền đọc cũng thấy, nó trở thành chỉ người thuộc nhóm đó mới thấy, và tất cả những người còn lại mất menu.
Bạn không nhận được cảnh báo nào, và người phát hiện ra thường là khách hàng vào sáng hôm sau.
Vì vậy quy tắc là trước khi lưu bất kỳ thay đổi nào liên quan tới menu, hãy mở chính menu đó ra xem phần nhóm quyền đang liệt kê những nhóm nào, và bổ sung đủ các nhóm cần thấy nó chứ không chỉ nhóm bạn đang làm.
Mặt trái của cái bẫy này cũng có thật. Khi bạn gán cho một nhóm quyền thấy một menu cha, chẳng hạn menu cấu hình của một phân hệ, thì người dùng nhóm đó tự động thấy luôn các menu con nằm dưới mà chưa được gán nhóm nào, miễn là họ đọc được đối tượng của menu con.
Trong đó có thể có những menu bạn không định cho họ thấy, chẳng hạn bảng giá nhập hàng. Cách xử lý là chủ động gán những menu con nhạy cảm đó cho một nhóm cụ thể để chúng ẩn đi với phần còn lại.
Menu trong Odoo có cấu trúc cha con, và cơ chế hiển thị của nó tinh tế hơn một chút so với cách người ta hay mô tả.
Một menu con hiện ra được thì nó tự kéo các menu cha của nó hiện lên theo, nên về lý thuyết bạn không phải gán từng cấp. Tuy nhiên chuỗi đó gãy ngay tại mắt xích nào đã được gán nhóm mà người dùng không thuộc. Menu gốc và menu trung gian của nhiều phân hệ, chẳng hạn Inventory, Purchase hay Accounting, đều đã được gán nhóm sẵn, nên trong thực tế bạn gần như luôn phải kiểm cả chuỗi từ cấp cao nhất xuống.
Dấu hiệu nhận ra cấu trúc chuỗi này là dấu gạch chéo trong tên đầy đủ của menu, mỗi dấu gạch là một cấp. Đây là loại lỗi khiến bạn ngồi kiểm rất lâu vì mọi thứ trông đều đúng, trong khi nguyên nhân chỉ là một cấp trung gian bị chặn.
Cái bẫy cuối nằm ở chỗ một màn hình thường không chỉ dùng một đối tượng dữ liệu.
Tình huống điển hình là bạn cấp đủ bốn quyền cho một nhóm trên đối tượng điều khoản thanh toán, người dùng vào được màn hình nhưng không thêm được dòng nào trong bảng các đợt thanh toán, hoặc thêm xong bấm lưu thì nhận thông báo lỗi quyền truy cập. Nguyên nhân là các dòng bên trong thuộc về một đối tượng khác, tức dòng điều khoản thanh toán, và nhóm đó chưa có quyền trên đối tượng kia.
Nguyên tắc rút ra là quyền trên đối tượng cha chưa đủ; hễ màn hình có một bảng dòng chi tiết thì phải kiểm luôn quyền trên đối tượng của các dòng đó.
Đi kèm là một chi tiết vận hành nhỏ mà bỏ qua thì bạn sẽ tưởng cấu hình của mình không chạy: sau mỗi lần đổi phân quyền, người dùng phải tải lại trang thì menu và màn hình mới cập nhật theo.
Tầng này giới hạn tập bản ghi mà người dùng được thao tác, và cần nói rõ ngay một chuyện hay bị hiểu ngược.
Tầng hai chỉ thu hẹp phần mà tầng một đã cho, chứ không bao giờ mở rộng vượt qua nó. Nếu tầng một đã không cho thì tầng hai không cứu được; ngược lại, nếu tầng một cho mà không có quy tắc nào ở tầng hai áp vào thì mặc định là cho.
Bên trong tầng hai còn một phân biệt đáng nhớ: quy tắc gắn với nhóm thì hợp lại với nhau, nên thuộc thêm một nhóm có quy tắc rộng hơn là thấy nhiều bản ghi hơn, còn quy tắc chung không gắn nhóm nào thì luôn thu hẹp cho tất cả mọi người.
Cấu trúc của một quy tắc giống tầng một ở chỗ cũng có bốn quyền, nhưng thêm phần điều kiện lọc để xác định tập bản ghi, và bốn ô ở đây mang nghĩa quy tắc áp cho thao tác nào chứ không phải cấp quyền. Ví dụ quen thuộc là một người có đủ bốn quyền trên đơn bán hàng ở tầng một, nhưng vì thuộc đội kinh doanh số một nên chỉ thấy và sửa được đơn của đội mình.
Phần điều kiện lọc là chỗ mà nhiều người dừng lại vì nó có cú pháp riêng. Có một mẹo bỏ qua được phần lớn chuyện cú pháp:
Mẹo này biến một việc kỹ thuật thành một việc thao tác, nên phần lớn quy tắc ở tầng hai nằm trong tầm tay người làm nghiệp vụ chứ không cần chuyển sang đội phát triển.
Tầng cuối cùng giới hạn ở mức từng trường trên màn hình, và đây chính là tầng giải được câu chuyện ở đầu bài.
Cách làm triệt để là khai báo nhóm quyền ngay trên định nghĩa của trường để người ngoài nhóm không đọc được trường đó ở bất kỳ đâu, và đây là việc của đội phát triển. Tuy nhiên nếu hệ thống có Studio thì người làm nghiệp vụ tự làm được một phần: mở Studio, bấm vào trường cần xử lý, rồi dùng một trong hai thuộc tính là cho phép hiển thị với một số nhóm, hoặc cấm hiển thị với một số nhóm.
Cần lưu ý rằng thuộc tính này của Studio được đặt riêng cho từng dạng xem, nên một trường bị ẩn trên form vẫn có thể hiện ra ở dạng danh sách, ở báo cáo hay ở chức năng xuất dữ liệu nếu bạn không xử lý cả những chỗ đó. Nói cách khác, đây là ẩn theo màn hình chứ chưa phải khóa trường ở tầng dữ liệu, và với những trường thật sự nhạy cảm như giá vốn thì nên đưa xuống đội phát triển.
Hai ví dụ nghiệp vụ hay gặp. Thứ nhất là trên màn hình báo giá, người của kho vào được nhưng không nên thấy đơn giá và các dòng tổng tiền, bởi họ chỉ quan tâm hàng hóa. Thứ hai là tab thông tin nhà cung cấp trên màn hình sản phẩm, thứ chỉ nên hiển thị với người phụ trách mua hàng.
Ngoài ra Studio thuộc bản Enterprise, nên với khách hàng dùng bản Community thì toàn bộ tầng ba quay lại là việc của đội phát triển.
Trước khi khép lại thì có một hiện tượng đáng biết để khỏi mất thời gian đi tìm nguyên nhân.
Có lúc bạn chỉ bỏ quyền đọc của một nhóm trên một đối tượng, không hề đụng tới menu, vậy mà sáng hôm sau người dùng báo mất menu. Không có gì sai cả, đó chính là cơ chế đã nói ở trên: menu hiển thị theo quyền đọc, nên mất quyền đọc là mất luôn menu. Còn thứ tự menu thì lấy từ số thứ tự khai báo trên chính menu, không phụ thuộc vào nhóm quyền của người dùng.
Bốn việc nên kiểm trước khi coi phần phân quyền là xong.
Riêng việc thứ tư thì đáng làm ngay cả khi bạn tự tin, vì chi phí của nó là mươi phút, còn chi phí của một lỗ hổng phân quyền phát hiện sau go-live thì tính bằng uy tín.
Phân quyền trả lời câu ai được làm gì trên dữ liệu; còn những việc hệ thống tự làm khi một bản ghi đổi trạng thái thì là chuyện của Automation Action, chủ đề của bài tiếp theo.
Thảo luận (0)
Bạn cần đăng nhập để thảo luận