web-dev-qa-db-ja.com

DDDの実装:ユーザーと権限

私は、ドメイン駆動設計の原則を理解しようとする小さなアプリケーションに取り組んでいます。成功した場合、これはより大きなプロジェクトのパイロットになる可能性があります。私は(Vaughn Vernonによる)本の「ドメイン駆動設計の実装」に従い、同様の簡単なディスカッションフォーラムを実装しようとしています。 githubのIDDDサンプルもチェックアウトしました。私のケースにアイデンティティとアクセスを採用するのにいくつかの困難があります。背景情報をいくつか挙げましょう。

  • 私は(うまくいけば)ユーザーとアクセス許可のロジックを分離する背後にある理由を理解しています。それはサポートドメインであり、異なる境界コンテキストです。
  • コアドメインには、ユーザーは存在せず、作成者、モデレーターのみが存在します。これらは、サービスを使用してIDおよびアクセスコンテキストに到達し、受信したユーザーオブジェクトをモデレーターに変換することによって作成されます。
  • ドメイン操作は、関連する役割をパラメーターとして呼び出されます。例:

    ModeratePost( ..., moderator);

  • ドメインオブジェクトのメソッドは、指定されたモデレーターインスタンスがnullでないかどうかを確認します(IDおよびアクセスコンテキストから要求されたユーザーにモデレーターの役割がない場合、モデレーターインスタンスはnullになります)。

  • 1つのケースでは、投稿を変更する前に追加のチェックを行います。

    if (forum.IsModeratedby(moderator))

私の質問は:

  • 後者の場合、セキュリティの懸念は再びコアドメインに組み込まれませんか?以前は、本には「誰が主題を投稿できるか、またはどのような条件で許可されているかが記載されています。フォーラムは、著者が今それを行っていることを知るだけで十分です」と述べています。

  • 本の役割ベースの実装はかなり単純です。モデレーターがコアドメインである場合、現在のuserIdをモデレーターインスタンスに変換するか、必要に応じて作成者に変換しようとします。ユーザーが必要な役割を持っていない場合、サービスは適切なインスタンスまたはnullで応答します。ただし、これをより複雑なセキュリティモデルにどのように適応させることができるかはわかりません。私が試用している現在のプロジェクトには、グループやACLなどのかなり複雑なモデルがあります。

「投稿はその所有者または編集者のみが編集する必要がある」のようなそれほど複雑ではないルールを使用しても、このアプローチは失敗するようです、または少なくとも私はそれを実装する正しい方法がわかりません。

OwnerOrEditorインスタンスのIdentity and Accessコンテキストを要求することは適切ではないと感じ、コアドメインにますます多くのセキュリティ関連クラスが存在することになります。さらに、userIdだけでなく、保護されたリソースの識別子(投稿やフォーラムのIDなど)をセキュリティコンテキストに渡す必要がありますが、これらはおそらくこれらのことを気にする必要はありません(正しいですか? )

コアドメインへのアクセス許可を取得し、それらをドメインオブジェクトのメソッドまたはサービスでチェックすることにより、ドメインとセキュリティの懸念を混在させることになります。

セキュリティとアクセス許可がコアドメイン自体でない限り、これらのアクセス許可に関連するものはコアドメインの一部であってはならないことをどこかで読みました(私はそれに同意する傾向があります)。上記のような単純なルールは、セキュリティをコアドメインの一部にすることを正当化しますか?

18
LittlePilgrim

実際のアクセス制御ルールと、アクセス制御の境界となるドメインの不変条件を区別するのは難しい場合があります。

特に、特定のドメインロジックの途中までしか利用できないデータに依存するルールは、ドメインから簡単に抽出できない場合があります。通常、Access Controlは、ドメイン操作が実行される前または後に呼び出されますが、その間は呼び出されません。

Vaughn Vernonのassert (forum.IsModeratedBy(moderator))の例は、おそらくドメインの外にあるはずですが、常に実行可能であるとは限りません。

UserIdだけでなく、保護されたリソースのID(投稿のID、フォーラムなど)をセキュリティコンテキストに渡す必要がありますが、これらはおそらくこれらのことを気にする必要はありません(正しいですか?)

セキュリティBCがあり、そのロジックを処理したい場合は、フォーラムの詳細を知る必要はありませんが、

  • 「モデレーター」のような概念の知識を持ち、それに応じてアクセス権を許可または拒否するだけです。
  • コアドメインイベントをサブスクライブし、それらをセキュリティBCが格納および使用するための単純な(リソース、authorizedUsers)キー値ペアに変換するアダプターロジックを使用できます。
7
guillaume31

認証と承認はDDDの悪い例です。

会社がセキュリティ製品を作成しない限り、これらはどちらもドメインの一部ではありません。

ビジネスまたはドメインの要件は、「ロールベースの認証が必要」です、またはそうする必要があります

次に、ドメイン関数を呼び出す前に役割を確認します。

「自分の投稿は編集できるが他の投稿は編集できない」などの複雑な要件がある場合は、ドメインで編集関数をEditOwnPost()EditOthersPost()に分けて、シンプルな関数にするようにします。ロールマッピングへ

機能をPoster.EditPost()Moderator.EditPost()などのドメインオブジェクトに分離することもできます。これは、よりOOPアプローチですが、メソッドはドメインサービスまたはドメインオブジェクトにあります。

ただし、ロールマッピングがドメイン外で発生するコードを分離することを選択します。たとえば、webapiコントローラがある場合:

PostController : ApiController
{
    [Authorize(Roles = "User")]
    public void EditOwnPost(string postId, string newContent)
    {
        this.postDomainService.EditOwnPost(postId, string newContent);
    }

    [Authorize(Roles = "Moderator")]
    public void EditOtherPost(string postId, string newContent)
    {
        this.postDomainService.EditOtherPost(postId, string newContent);
    }
}

ご覧のとおり、役割のマッピングはホスティングレイヤーで行われますが、ownまたはothersの投稿の編集を構成する複雑なロジックはドメインの一部です。

ドメインはアクションの違いを認識しますが、セキュリティ要件は単純に"機能はロールによって制限される可能性があります"です。

これはおそらくドメインオブジェクトの分離でより明確になりますが、本質的には、サービスメソッドを呼び出すメソッドではなく、オブジェクトを構築するメソッドをチェックしています。ドメインの一部として引き続きそれを表明したい場合の要件は次のようになります'モデレーターのみがモデレーターオブジェクトを作成できます'

5
Ewan

私は同じ質問に出くわし、議論が少し前に行われたとしても(それでもGoogleのトピックの2番目のリンクです)、トピックにいくつかの追加のビジョンを与える可能性があるため、思いついた答えを投稿しています。

私は、2つの異なる種類のアクセス制御があると思います。

  • 認証スキームに関するロール検証
  • ビジネス用語でのアクション検証

特定のユーザーがモデレーターかどうかを知るは、アイデンティティとアクセスの制限付きコンテキストに属します。それは、ユーザーが持っている権利、つまりそのカテゴリーと関係があるからです。

だが

モデレーターが投稿を編集できるかどうかを確認するはビジネスドメインに属し、IDとアクセスの制限付きコンテキスト外である必要があります。これを確認する良い方法は、ターゲットユーザーを参照せずに条件が表現されていることです。たとえば、モデレーターが別のモデレーターの投稿を編集できるかどうかはビジネスルールです。 Identity&Access BCを汚染しないようにする必要があります。

OAuth設定のscopesにこの推論を適用する場合、特に明確になります。認証ルールに加えて、次の条件に基づいてアクションを承認する必要があります。特定のスコープがトークン要求に含まれているか含まれていない場合、どこに配置しますか?

それをビジネスBCに置いたと思います。これは、スコープのセマンティクスがビジネスドメインに認識されているためです。特定の役割を持ち、それによって何ができるかを知ることは、2つの異なる問題です。最初の部分はI&A BCにあり、2番目の部分はビジネスドメインにあります。

そして、それは正しいと感じます:モデレーターによるトピックの編集を突然禁止したい場合は、I&A BCではなくフォーラムBCを変更する必要があります-実際にはロールの定義に何も変更されていません。変更されたのは、特定のBCのセマンティクスだけです。

そのため、ビジネスBCでif (forum.IsModeratedby(moderator))をチェックするのが最善のソリューションだと思います。私はその問題に関して受け入れられた答えに同意しないと思います。

そのような多くのルールが特定のビジネスBCに存在する場合、ビジネスBCのサブドメインにそれらをバンドルすることが最善の方法であると私には思われます。そのようなビジネスルールは、(Strategyパターンのように)呼び出すオブジェクトとして具体化することでメリットを得られます。

1
Qortex