Tóm lược
Có nên thực hiện ủy quyền trong CQRS / DDD cho mỗi lệnh / truy vấn hay không?
Tôi đang phát triển lần đầu tiên một ứng dụng trực tuyến sử dụng mô hình DDD CQRS ít nhiều nghiêm ngặt. Tôi đã gặp phải một số vấn đề mà tôi không thể thực sự hiểu được.
Ứng dụng tôi đang xây dựng là một ứng dụng sổ cái cho phép mọi người tạo sổ cái, cũng như cho phép người khác xem / chỉnh sửa / xóa chúng, chẳng hạn như nhân viên. Người tạo ra một sổ cái sẽ có thể chỉnh sửa quyền truy cập của sổ cái mà anh ta đã tạo. Thậm chí có thể thay đổi quyền sở hữu. Tên miền có hai tập hợp TLedger và TUser .
Tôi đã đọc rất nhiều bài đăng với từ khóa DDD / CQRS liên quan đến bảo mật, ủy quyền, v.v. Hầu hết trong số họ nói rằng ủy quyền là một Subdomain chung , trừ khi một người đang xây dựng một ứng dụng bảo mật.
Trong trường hợp này, miền lõi chắc chắn là một miền kế toán quan tâm đến các giao dịch, số dư và tài khoản. Nhưng chức năng của việc có thể quản lý truy cập chi tiết tốt vào sổ cái cũng được yêu cầu. Tôi đang tự hỏi làm thế nào để thiết kế điều này theo thuật ngữ DDD / CQRS.
Điều này được nêu trong các hướng dẫn DDD ở khắp nơi rằng các lệnh là một phần của ngôn ngữ phổ biến. Chúng có ý nghĩa. Chúng là những hành động cụ thể đại diện cho "hàng thật".
Bởi vì tất cả các lệnh và truy vấn đó là hành động thực tế mà người dùng sẽ thực hiện trong "đời thực", nên việc thực thi ủy quyền có được kết hợp với tất cả các "lệnh" và "truy vấn" này không? Một người dùng sẽ có quyền thực thi TLedger.addTransaction () chứ không phải TLedger.removeTransaction (). Hoặc, người dùng sẽ được phép thực hiện truy vấn "getSummaries ()" chứ không phải "getTransilities ()".
Ánh xạ ba chiều sẽ tồn tại dưới dạng lệnh người dùng-sổ cái hoặc lệnh người dùng-truy vấn để xác định quyền truy cập.
Hoặc, theo cách tách rời, "quyền" có tên sẽ được đăng ký cho người dùng. Quyền mà sau đó sẽ được ánh xạ cho các lệnh cụ thể. Ví dụ: quyền "ManageTransilities" sẽ cho phép người dùng thực thi "AddTransaction ()", "RemoveTransaction ()", v.v.
Người dùng ánh xạ quyền -> sổ cái -> lệnh / truy vấn
Người dùng ánh xạ quyền -> sổ cái -> quyền -> lệnh / truy vấn
Đó là phần đầu tiên của câu hỏi. Hay nói ngắn gọn, ủy quyền trong CQRS / DDD nên được thực hiện theo lệnh hoặc mỗi truy vấn? Hoặc, ủy quyền nên được tách rời khỏi các lệnh?
Thứ hai, liên quan đến ủy quyền dựa trên sự cho phép. Người dùng sẽ có thể quản lý các quyền trên Sổ cái của mình hoặc trên Sổ cái mà anh ta được phép quản lý.
- Các lệnh quản lý ủy quyền xảy ra trong Sổ Cái
Tôi đã nghĩ đến việc thêm các sự kiện / lệnh / trình xử lý vào tập hợp Ledger , chẳng hạn như GrantPermission (), revokePermission (), v.v. Trong trường hợp này, việc thực thi các quy tắc đó sẽ xảy ra với các trình xử lý lệnh. Nhưng điều này sẽ yêu cầu tất cả các lệnh bao gồm id của người dùng đã ban hành lệnh đó. Sau đó, tôi sẽ kiểm tra vào TLedger nếu có sự cho phép của người dùng đó để thực thi lệnh đó.
Ví dụ :
class TLedger{
function addTransactionCmdHandler(cmd){
if (!this.permissions.exist(user, 'addTransaction')
throw new Error('Not Authorized');
}
}
- Các lệnh quản lý ủy quyền trong Người dùng
Một cách khác là bao gồm các quyền vào TUser. Một TUser sẽ có một bộ quyền. Sau đó, trong trình xử lý lệnh TLedger, tôi sẽ truy xuất người dùng và kiểm tra xem anh ta có được phép thực thi lệnh không. Nhưng điều này sẽ yêu cầu tôi lấy tổng hợp TUser cho mỗi lệnh TLedger.
class TAddTransactionCmdHandler(cmd) {
this.userRepository.find(cmd.userId)
.then(function(user){
if (!user.can(cmd)){
throw new Error('Not authorized');
}
return this.ledgerRepository.find(cmd.ledgerId);
})
.then(function(ledger){
ledger.addTransaction(cmd);
})
}
- Một tên miền khác có dịch vụ
Một khả năng khác là mô hình hóa một miền ủy quyền hoàn toàn khác. Tên miền này sẽ quan tâm đến quyền truy cập, ủy quyền, v.v ... Tên miền phụ kế toán sau đó sẽ sử dụng một dịch vụ để truy cập miền ủy quyền này dưới dạng AuthorizationService.isAuthorized(user, command)
.
class TAddTransactionCmdHandler(cmd) {
authService.isAuthorized(cmd)
.then(function(authorized){
if (!authorized) throw new Error('Not authorized');
return this.ledgerRepository.find(cmd.ledgerId)
})
.then(function(){
ledger.addTransaction(cmd);
})
}
Quyết định nào sẽ là cách "DDD / CQRS" nhất?