Domain driven design 从其他有界上下文验证日期

Domain driven design 从其他有界上下文验证日期,domain-driven-design,cqrs,Domain Driven Design,Cqrs,我有两个有界上下文(学生集合,课程)。 学生名册上所有的学生都有他的课程证和家庭作业。 课程的管理部分包含与课程相关的所有信息。 当学生想要获取课程信息时,它会点击发送jwt令牌的端点(/courses/ID)。在课程上下文中,我获取学生ID、课程ID并创建查询,该查询在总线中调度。在从课程ID获取课程信息之前的查询处理程序中,我想验证学生ID是否存在,以及该学生是否拥有该课程。为此,我不得不称之为另一个上下文受限的studentenroll。所以,我在寻找如何在互联网上处理这个问题,我发现:

我有两个有界上下文(学生集合,课程)。 学生名册上所有的学生都有他的课程证和家庭作业。 课程的管理部分包含与课程相关的所有信息。 当学生想要获取课程信息时,它会点击发送jwt令牌的端点(/courses/ID)。在课程上下文中,我获取学生ID、课程ID并创建查询,该查询在总线中调度。在从课程ID获取课程信息之前的查询处理程序中,我想验证学生ID是否存在,以及该学生是否拥有该课程。为此,我不得不称之为另一个上下文受限的studentenroll。所以,我在寻找如何在互联网上处理这个问题,我发现:

你觉得怎么样

已更新

namespace App\Context\Course\Module\Course\UI\Controller;

class GetCourseController extends Controller
{
    public function getAction($request) {
        $this->ask(new FindByCourseIdQueryHandler($request->get('course_id'));
    }
}

namespace App\Context\Course\Module\Course\Infrastracture\Query;

class AuthorizedQueryDispatcher extends QueryDispatcher
{
    //In this case $query would be FindByCourseIdQueryHandler
    public function handle($query)
    {
        $authUser = $this->oauthService->getAuthUser();

        //it can be student or teacher
        $role = $authUser->getRole();
        $userId = $authUser->getUserId();

        //it will return FindByCourseIdAndStudentIdAuthorizedQueryHandler
        $authorizedQuery = $this->inflector->getAuthorizedQueryName->from($userId, $role, $query);

        $this->dispatch($authorizedQuery);

        $this->queryDispatch->dispatch($query);
    }
}

namespace App\Context\Course\Module\Course\Application\Query;

class FindByCourseIdAndStudentIdAuthorizedQueryHandler
{
    public function handle($findByCourseIdAndStudentIdQuery)
    {
        $student = $this->studentEnrollmentClient->getStudentFrom($findByCourseIdAndStudentIdQuery->courseId, $findByCourseIdAndStudentIdQuery->studentId);

        if (!$student) {
            throw new InvalidStudentException();
        }
    }
}

namespace App\Context\Course\Module\Course\Application\Query;

class findByCourseIdAndStudentIdQueryHandler()
{
    public function handle($findByCourseIdQueryHandler)
    {
        $courseId = $findByCourseIdQueryHandler->courseId();

        $this->courseRepository->findByCourseId($courseId);
    }
}

TLDR;授权应该与域层明确分开,例如在不同的包/命名空间/模块中。此外,域与授权之间的依赖关系应该颠倒,域不应该依赖/了解授权/

实现它的一种方法是创建一个授权服务,例如
findbycourseandstudentidqueryauthorizer
(我们称之为Authorizer)。此服务可能跨越有界上下文(BC)边界,即它可能依赖于来自远程BC的远程域服务。理想情况下,当授权人进行检查时,远程数据应该已经可用。通过这种方式,系统在远程有界上下文服务不可用的情况下更具弹性。您可以通过监听远程事件或后台任务来实现这一点

理想情况下,域层(来自任何BC)不应该知道授权者

一种方法是使用授权的QueryDispatcher在应用程序的合成根目录中修饰QueryDispatcher(或您拥有的)。这个AuthorizedQueryDispatcher,当它收到一个查询时,它首先搜索一个授权者,然后调用它。如果授权失败,则拒绝查询。如果授权成功或没有授权人,则查询将发送到real/Defended QueryDispatcher


如果不能做到这一点(即,您没有QueryDispatcher),那么您可以尝试装饰每个查询处理程序(手动)。例如,您可以有一个
findbycourseandstudentidauthorizedqueryhandler
,它与
findbycourseandstudentidqueryhandler
具有相同的接口。您可以在应用程序的合成根目录(DIC)中替换它们。

因此,您有一个授权建模问题,对吗?不太对,我正在使用LexikJWTAuthenticationBundle处理授权。它在执行控制器之前有一些侦听器,该控制器从头恢复令牌并从令牌创建userAuth。然后在控制器中,我从userAuth获取学生id,并在查询中设置它。我的问题是:如果使用collaboratorService检索属于另一个有界上下文的学生是好的。因为我的理解是collaboratorService是用于授权的。但在我的例子中,我用它来检索一个学生。授权而不是认证,它们是不同的。我试图看看你有什么问题,这样我可以给你一个正确的答案。我的问题是,我需要知道这个学生是否有课程,让他获得课程信息。但是,学生与课程之间的关系是在另一个有限的语境中(学生集合)。所以我把逻辑放在collaboratorService里面,我根据你说的更新了我的问题,可以吗?看一看namesapce@AgustinCastro是的,但我会以某种方式使用更多的抽象,比如装饰师patterin我应该使用更多的抽象哪个部分?@AgustinCastro,例如,我会装饰队列处理器
namespace App\Context\Course\Module\Course\UI\Controller;

class GetCourseController extends Controller
{
    public function getAction($request) {
        $this->ask(new FindByCourseIdQueryHandler($request->get('course_id'));
    }
}

namespace App\Context\Course\Module\Course\Infrastracture\Query;

class AuthorizedQueryDispatcher extends QueryDispatcher
{
    //In this case $query would be FindByCourseIdQueryHandler
    public function handle($query)
    {
        $authUser = $this->oauthService->getAuthUser();

        //it can be student or teacher
        $role = $authUser->getRole();
        $userId = $authUser->getUserId();

        //it will return FindByCourseIdAndStudentIdAuthorizedQueryHandler
        $authorizedQuery = $this->inflector->getAuthorizedQueryName->from($userId, $role, $query);

        $this->dispatch($authorizedQuery);

        $this->queryDispatch->dispatch($query);
    }
}

namespace App\Context\Course\Module\Course\Application\Query;

class FindByCourseIdAndStudentIdAuthorizedQueryHandler
{
    public function handle($findByCourseIdAndStudentIdQuery)
    {
        $student = $this->studentEnrollmentClient->getStudentFrom($findByCourseIdAndStudentIdQuery->courseId, $findByCourseIdAndStudentIdQuery->studentId);

        if (!$student) {
            throw new InvalidStudentException();
        }
    }
}

namespace App\Context\Course\Module\Course\Application\Query;

class findByCourseIdAndStudentIdQueryHandler()
{
    public function handle($findByCourseIdQueryHandler)
    {
        $courseId = $findByCourseIdQueryHandler->courseId();

        $this->courseRepository->findByCourseId($courseId);
    }
}