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


16

私は、ドメイン駆動設計の原則を把握しようとする小さなアプリケーションに取り組んでいます。成功した場合、これは大規模プロジェクトのパイロットになる可能性があります。「Implementing Domain-Driven Design」(Vaughn Vernon著)を読み、同様のシンプルなディスカッションフォーラムを実装しようとしています。また、githubでIDDDサンプルをチェックアウトしました。私は自分のケースにアイデンティティとアクセスを採用するのに苦労しています。背景情報をいくつかご紹介します。

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

    ModeratePost( ..., moderator);

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

  • ある場合には、投稿を変更する前に追加のチェックを行います:

    if (forum.IsModeratedby(moderator))

私の質問は:

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

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

「投稿はその所有者または編集者のみが編集する必要があります」のようにあまり複雑ではないルールでさえ、このアプローチは破綻しているように見えます。

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

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

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


たぶん、ここで必要なものを見つけることができます:stackoverflow.com/a/23485141/329660また、アクセス制御コンテキストがリソースIDを知っているからといって、そのリソースがどのような種類のエンティティであるか、それが何であるかについてのドメイン知識があるわけではありませんします。
-guillaume31

おかげで、以前にその投稿を見ましたが、私の問題は最後に編集が言っていることです:アクセス制御をコアドメインの外に移動したいのですが、実装で壁にぶつかったと感じています。ただし、リソースIDについての提案は理にかなっています:コアドメインではユーザーまたはロールの概念ではなく具体的​​なロールを使用しているため、セキュリティBCでリソースの概念を使用して関連する具体的なマップにマッピングできますドメインの概念。試してみる価値あり、ありがとう!
LittlePilgrim

リンク内のコードサンプルは、少なくとも「これをより複雑なセキュリティモデルにどのように適合させることができるかわかりません」に対する回答ではありませんか?
-guillaume31

私の問題は、セキュリティモデル自体の実装にあるのではなく、これらのより複雑なルールをドメインにどのようにマップすべきかわかりません。セキュリティ側の単純なロールベースのモデルではない場合、ユーザー->作成者のマッピングをどのように変更する必要がありますか?リソースIDを他のコンテキストに渡すHasPermissionToEdit(userId, resourceId)ことはうまくいくかもしれませんが、これらの呼び出しでドメインロジックを汚染するのは適切ではないと感じます。ドメインロジックを呼び出す前に、おそらくアプリケーションサービスメソッドでこれらをチェックする必要がありますか?
LittlePilgrim

もちろん、それはアプリケーションサービス内にあるはずです... UserService @AccessControlList[inf3rno]リンクした回答のように、コードの一部からは明らかだと思いました。
guillaume31

回答:


6

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

特に、特定のドメインロジックの過程で使用可能なデータのみに依存するルールは、ドメインから簡単に抽出できない場合があります。通常、アクセス制御はドメイン操作の実行前または実行後に呼び出されますが、実行中は呼び出されません。

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

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

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

  • 「moderated by」などの概念の知識があれば、それに応じてアクセス権を許可または拒否できます。
  • コアドメインイベントをサブスクライブし、セキュリティBCが保存および使用するための単純な(リソース、authorizedUsers)キー値ペアに変換するアダプターロジックを使用できます。

両方の答えが有用であり、多かれ少なかれ同じ方向を指しているので、私は両方に賛成しました。@ guillaume31がVernonの実装に関する私の質問に多かれ少なかれ答えているので、これを受け入れました。SecurityBCでのリソースの使用に関する彼のヒントに基づいて実装を続行します。
LittlePilgrim

これは私の答えとは正反対にあると思います。
ユアン

1
多分私は今ではあまりにも混乱しているかもしれませんが、私の解釈は(両方の答えに対して):1.セキュリティの懸念をドメインから排除し、セキュリティBCをサービスとして使用します2.ドメインオブジェクトを呼び出す前にサービスを呼び出します3.サービスユーザー/ aclsからモデレーター、作成者などへのマッピングを行います。4. moderator = securityService.GetModerator(userId, forumId) moderator.EditPost()のように、これらのオブジェクトにドメインロジックが実装されます。そこ
LittlePilgrim

私はまだこれに関する回答/指示を探していますが、オブジェクトの現在の状態に依存する承認ロジック(モデレーターに現在割り当てられている場合など)は、実際にはさらに、ドメインがドメイン内にない場合、モデルを同時に更新できると、無効な状態になるリスクがあります。たとえば、ポリシーを使用して所有権を検証し、そのオブジェクトを更新する場合-多くのドメインでは、所有権が変更される可能性があり、アクションが無効になる場合があります。
ヨルダン

非常に複雑なコラボレーションコンテキストがない限り、バージョニングを使用してここに楽観的同時実行モデルを実装する余裕がありますが、チェックが特定の集約インスタンス内で、または少なくとも特定の集約インスタンスに対して行われない場合、実際のチェックと一貫性がない可能性があります変更を永続化するまでのオブジェクトの状態。
ヨルダン

5

認証と承認は、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);
    }
}

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

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

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


4
役割を「静的に」チェックすることは少し単純化されています。モデレーターが別のモデレーターの投稿を編集できない場合はどうなりますか?このチェックはドメインの一部ではありませんか?
レダHousni Alaoui

2
@RédaHousniAlaoui私もこれについて疑問に思っています。ドメイン内のユーザー/モデレーターの言及を含めるか、そのApiController内で何らかのロジックを実行して投稿の作成者の役割を取得する以外に、これを処理する方法は考えられません。これらはどちらも正しくないと思われますが、これは私の経験では一般的なものであり、明確なガイダンスが非常に役立ちます。
ジミー

1
@Erwan、私が話しているユースケースは動的です。「認証と承認はDDDの悪い例です」という文章をhello worldの例に基づいて作成するのは不正です。DDDは、偶発的な複雑さを回避し、ドメインの複雑さを管理できるようにするためのものです。動的なアクセス許可は、偶発的な複雑さでも、実際には発生しないことでもありません。
レダHousni Alaoui

1
私見、あなたのソリューションの問題は、顧客を満足させないことです。多くの場合、顧客はこれらの関係を動的に変更できることを望んでいます。また、ベンダーが異なる企業に同じエンタープライズソフトウェアを提供する場合にも発生します。ソフトウェアの調整が不十分な場合、ベンダーは最終的に死にます。
レダHousni Alaoui

1
「しかし、一般に「悪いこと」として認識されており、セキュリティ設定は時間の経過とともに管理不能になり、アプリが安全でなくなることを意味します。」正しい設計とテストにより、完全に管理可能です。しかし、私のXPから、正しい設計を作成するために、ドメインは許可を確認する必要があります。代替手段はユートピアです。
レダHousni Alaoui
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.