DDD CQRS-クエリごとおよびコマンドごとの承認


15

概要

CQRS / DDDの承認は、コマンド/クエリごとに実装する必要がありますか?

多かれ少なかれ厳密にDDD CQRSパターンを使用するオンラインアプリケーションを初めて開発しています。私はいくつかの問題にぶつかりましたが、それを本当に回避することはできません。

私が作成しているアプリケーションは、元帳アプリケーションで、元帳を作成できるほか、従業員など他の人が元帳を表示/編集/削除できます。元帳の作成者は、作成した元帳のアクセス権を編集できる必要があります。所有権を変更することさえできます。ドメインには、TLedgerTUserの 2つの集約があります

セキュリティ、認可などに関するDDD / CQRSキーワードを含む多くの投稿を読みました。それらのほとんどは、セキュリティアプリケーションを構築していない限り、認可はGeneric Subdomainであると述べました。

この場合、コアドメインは確かに、トランザクション、バランシング、アカウントに関心のあるアカウンティングドメインです。ただし、元帳へのきめ細かいアクセスを管理できる機能も必要です。これをDDD / CQRSの用語でどのように設計するのか疑問に思っています。

コマンドがユビキタス言語の一部であるということは、DDDチュートリアルの至る所で述べられています。それらは意味があります。それらは「本物」を表す具体的なアクションです。

これらのコマンドとクエリはすべて、ユーザーが「実際に」実行する実際のアクションであるため、承認の実装をこれらすべての「コマンド」および「クエリ」と組み合わせる必要がありますか?ユーザーには、たとえばTLedger.addTransaction()を実行する権限がありますが、TLedger.removeTransaction()は実行できません。または、ユーザーはクエリ「getSummaries()」を実行できますが、「getTransactions()」は実行できません。

アクセス権を決定するために、user-ledger-commandまたはuser-ledger-queryの形式で3次元マッピングが存在します。

または、切り離された方法で、「permissions」という名前がユーザーに登録されます。特定のコマンド用にマップされる許可。たとえば、権限「ManageTransactions」では、ユーザーは「AddTransaction()」、「RemoveTransaction()」などを実行できます。

  1. 権限マッピングユーザー->元帳->コマンド/クエリ

  2. パーミッションマッピングユーザー->元帳->パーミッション->コマンド/クエリ

それが質問の最初の部分です。または、簡単に言えば、CQRS / DDDの承認はコマンドごとまたはクエリごとに実装する必要がありますか?または、許可をコマンドから分離する必要がありますか?

第二に、許可に基づいた認可について。ユーザーは、自分の元帳または管理が許可されている元帳の権限を管理できる必要があります。

  1. 元帳で許可管理コマンドが発生する

grantPermission()、revokePermission()などのイベント/コマンド/ハンドラーをLedger集計に追加することを考えました。この場合、これらのルールの強制はコマンドハンドラーで発生します。ただし、これにはすべてのコマンドに、そのコマンドを発行したユーザーのIDを含める必要があります。次に、そのコマンドを実行する権限がそのユーザーに存在する場合、TLedgerをチェックインします。

例えば ​​:

class TLedger{ 
    function addTransactionCmdHandler(cmd){
        if (!this.permissions.exist(user, 'addTransaction')
            throw new Error('Not Authorized');
    }
}
  1. ユーザーの許可管理コマンド

もう1つの方法は、TUserにアクセス許可を含めることです。TUserには一連の権限があります。次に、TLedgerコマンドハンドラーでユーザーを取得し、コマンドを実行する権限があるかどうかを確認します。しかし、これには、すべてのTLedgerコマンドのTUser集計を取得する必要があります。

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. サービスを持つ別のドメイン

別の可能性は、別の許可ドメインを完全にモデル化することです。このドメインは、アクセス権、承認などに関心があります。会計サブドメインは、サービスを使用して、この承認ドメインにの形式でアクセスします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);
    })

}

どの決定が最も「DDD / CQRS」の方法でしょうか?


1
すばらしい質問です-私は同様の問題に取り組んでいますが、どの文献もそれを直接扱っていないようです。あなたの質問の後半で少し混乱しました。許可の管理(許可の追加または削除)をどこに置くべきか疑問に思っているように見えますが、示されている例はトランザクションを追加するためのものです。その部分を明確にしてください。
-emragins

各トランザクションには実行ポリシーがあります。各ユーザーは1つ以上のグループに属している必要があります。各グループには、許可されるトランザクションを指定するアクセスプロファイルがあります。実行時に、トランザクションを実行する前に、実行中のユーザーの集約プロファイルに対してポリシーがチェックされます。もちろん、これは言うよりも簡単です。
-NoChance

回答:


5

最初の質問については、似たようなことに苦労しています。私はますます3段階の認可スキームに傾いています:

1)のコマンド/クエリレベルでの認可は、「このユーザーがない今までにこのコマンドを実行する権限を持っています?」MVCアプリでは、これはおそらくコントローラーレベルで処理できますが、現在のユーザーと実行中のコマンドに基づいてアクセス許可ストアを照会する汎用プリハンドラーを選択しています。

2)「このユーザーは「このエンティティにアクセスする許可を持っていますか?」というアプリケーションサービス内での承認。私の場合、これはおそらくリポジトリのフィルターによる暗黙的なチェックになります-私のドメインではこれは基本的に、OrganizationIdのもう少し詳細なTenantIdです。

3)エンティティの一時的なプロパティ(ステータスなど)に依存する承認は、ドメイン内で処理されます。(例:特定の人のみがクローズドレジャーを変更できます。)ドメインとビジネスロジックに大きく依存しているため、それをドメイン内に配置することを選択します。

私はこのアイデアに対する他の人の反応を聞きたいです-あなたが望むならそれを細断します(あなたがそうするならいくつかの選択肢を提供してください:))


承認のさまざまな「レイヤー」に関して、いくつかの有効なポイントがあると思います。私が取り組んでいたシステムには、登録ユーザーとスタッフメンバーという異なるタイプのユーザーがいました。コマンド/クエリハンドラーのアクセス許可は、ユーザータイプの基本的なチェックを行いました。スタッフだったら、いつも通り抜けていた。登録ユーザーである場合、特定の条件が満たされた場合にのみ許可されました(たとえば、集約に対する許可)。
マグナス

0

認可BCの一部として認可を実装しますが、アクションフィルターとしてLedgerシステムにデプロイします。このようにして、それらは互いに論理的に分離できます-元帳コードは認証コードを呼び出す必要はありませんが、それでも各着信リクエストの高性能なインプロセス認証を取得できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.