DDD CQRS - ủy quyền cho mỗi truy vấn và mỗi lệnh


15

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 TLedgerTUser .

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.

  1. Người dùng ánh xạ quyền -> sổ cái -> lệnh / truy vấn

  2. 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ý.

  1. 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');
    }
}
  1. 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);
    })

}
  1. 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?


1
Câu hỏi tuyệt vời - Tôi đã cố gắng giải quyết các vấn đề tương tự và dường như không có tài liệu nào đề cập trực tiếp đến nó. Tôi hơi bối rối bởi nửa sau câu hỏi của bạn. Nghe có vẻ như bạn đang tự hỏi về việc đặt quản lý quyền ở đâu (thêm hoặc xóa các hoán vị) nhưng các ví dụ được hiển thị là để thêm giao dịch, vì vậy có vẻ như nửa sau đang hỏi "tôi nên truy vấn quyền như thế nào". Bạn có thể làm rõ phần đó xin vui lòng?
emragins

Mỗi giao dịch có thể có chính sách thực hiện. Mỗi người dùng nên thuộc về một nhóm quặng hơn, mỗi nhóm sẽ có một hồ sơ truy cập chỉ định giao dịch nào được phép. Tại thời điểm chạy, trước khi thực hiện giao dịch, chính sách được kiểm tra đối với các cấu hình tổng hợp cho người dùng thực thi. Tất nhiên, nói bao giờ cũng dễ hơn làm.
NoChance

Câu trả lời:


5

Đối với câu hỏi đầu tiên tôi đã vật lộn với một cái gì đó tương tự. Càng ngày tôi càng nghiêng về một kế hoạch ủy quyền gồm ba giai đoạn:

1) Ủy quyền ở cấp lệnh / truy vấn của "người dùng này có bao giờ được phép thực thi lệnh này không?" Trong một ứng dụng MVC, điều này có thể có thể được xử lý ở cấp điều khiển, nhưng tôi đang chọn một trình xử lý trước chung sẽ truy vấn kho lưu trữ quyền dựa trên người dùng hiện tại và lệnh thực thi.

2) Ủy quyền bên trong dịch vụ ứng dụng của "người dùng này" có bao giờ * có quyền truy cập thực thể này không? "Trong trường hợp của tôi, đây có thể sẽ là một kiểm tra ngầm chỉ bằng các bộ lọc trên kho lưu trữ - trong miền của tôi, đây là về cơ bản là một TenantId với độ chi tiết cao hơn một chút của Organis.

3) Việc ủy ​​quyền dựa trên các thuộc tính thoáng qua của các thực thể của bạn (chẳng hạn như Trạng thái) sẽ được xử lý bên trong miền. (Vd

Tôi rất thích nghe phản hồi của người khác về ý tưởng này - xé nó thành vụn nếu bạn muốn (chỉ cung cấp một số lựa chọn thay thế nếu bạn làm :))


Tôi nghĩ rằng bạn có một số điểm hợp lệ liên quan đến các "lớp" ủy quyền khác nhau. Một hệ thống tôi đang làm việc có nhiều loại người dùng khác nhau - người dùng đã đăng ký và nhân viên. Các quyền xử lý lệnh / truy vấn đã kiểm tra cơ bản về loại người dùng. Nếu đó là nhân viên, nó luôn luôn đi qua. Nếu đó là người dùng đã đăng ký thì nó chỉ được phép nếu đáp ứng một số điều kiện nhất định (ví dụ: quyền trên tổng hợp).
Magnus

0

Tôi sẽ triển khai ủy quyền như một phần của Ủy quyền BC của bạn nhưng triển khai nó dưới dạng bộ lọc hành động vào hệ thống Sổ Cái của bạn. Bằng cách này, chúng có thể được tách rời một cách hợp lý với nhau - mã Ledger của bạn không cần phải gọi mã Ủy quyền - nhưng bạn vẫn nhận được ủy quyền trong quá trình hiệu suất cao cho mỗi yêu cầu đến.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.