Design patterns 一个人是否应该拥有在其内部或外部更改域的设计权限?

Design patterns 一个人是否应该拥有在其内部或外部更改域的设计权限?,design-patterns,authorization,domain-driven-design,cqrs,Design Patterns,Authorization,Domain Driven Design,Cqrs,以下是域类: class AuthorAR { private $authorId; } class BookAR { private $bookId; // book owner private $authorId; private $title; public function changeTitle($title) { $this->title = $title; } } // This will be i

以下是域类:

class AuthorAR {
    private $authorId;
}

class BookAR {
    private $bookId;
    // book owner
    private $authorId;
    private $title;

    public function changeTitle($title) {
        $this->title = $title;
    }
}

// This will be in the domain layer to make explicit the finding of the book
interface BookRepository {
    public function findByBookId($bookId);
    public function findForAuthorIdByBookId($authorId, $bookId);
}  
以下是用于域外授权的Dao类:

class AuthorizationDao {
    public function findBookOfIdForAuthorId($bookId, $authorId) {}
}  
以下是我在一些地方看到的两种方法,我不知道哪一种更好,哪一种被认为是好的做法(这只是一个简单的例子,主要问题是将这种授权放在哪里):


那么如何设计这种类型的权限检查(授权)?在允许BookAR更改其状态之前,如果特定作者是书籍的所有者,如何设计验证(在CQR中,不需要查询权限,只需要状态更改权限)?简短回答:

您应该将业务逻辑与授权逻辑分开。 为什么?它使它:

  • 易于维护
  • 易于发展和更新
  • 更容易运行有关用户在系统中可以执行的操作的审核报告
长答案:

我已经围绕这个主题提供了一些关于堆栈溢出的答案:

在这些回答中,我介绍了基于属性的访问控制(ABAC)和外部化授权管理的概念。关键是:

  • 您应该避免实现自定义代码以实现授权
  • 您应该清楚地将业务逻辑与授权逻辑分开
现有的授权模型(RBAC…)过于以用户为中心,无法满足您的需求。您需要在图书所有者和试图对图书采取行动的用户之间建立关系

ABAC中的步骤。ABAC使用属性(用户、对象、操作和上下文)以技术无关的方式定义授权策略,例如:

  • 当且仅当book.owner==user.id时,用户才能编辑书籍的元数据
NIST最近在ABAC上发布了一篇文章,我建议你去看看。XACML是可扩展访问控制标记语言,是ABAC的实际实现。XACML定义:

  • 建筑
  • 政策语言,以及
  • 请求/响应方案

您可以在上以及上找到更多关于XACML的资源。

我不喜欢授权模式,因为授权模式会使您在域外的层中泄漏业务逻辑。由于我在CQRS上下文中使用DDD,这些授权策略中的大多数将在域模型中实现:Author->createAuthor->generateAuthordFromUser(){if(!User.isActive()throw DomainException…}。大多数授权规则实际上是业务规则。实际授权是允许用户访问资源的授权,如果它是所有者或权限是由管理员授予的。另一个例子是购物车。可能有一条业务规则规定,没有人可以向购物车添加超过10个项目,但任何人都可以向购物车添加项目。这是由与User.isActive()域描述相同的业务表示的限制。因此,基本上任何人都可以访问addItemToCart()命令,但如果购物车中已经有10个项目,则不可能完全填充此命令(因此它甚至不应该在UI中可用)。至于CQR,这应该在域中表示,并且您在应用程序的读取/查询端(资源访问)中的身份验证类型。我也同意ABAC比RBAC更好,但这当然取决于业务/应用程序的需要。我不相信ABAC,因为它可能会泄露一些域模型(DDD)之外的业务规则。ABAC似乎从域层(DDD/CQR)删除了大部分业务规则。我认为ABAC适合于应用程序的查询端,而不是写/命令端,在写/命令端,大多数规则(如果不是全部的话)都将位于域层。另一个注意事项:如果ShoppingCart有10个以上的产品处于无效状态(域业务规则拒绝addItemCommand),如果User.isNotActive()域将拒绝从尚未完成付款的个人(用户)创建新作者(即活动域描述)。这些都是域业务规则,而不是授权规则。这些规则允许或拒绝某些命令来修改域的状态。如果我用ABAC阅读正确,这些规则将位于域外的Ahtorization层,这似乎与DDD规则相矛盾。我同意你的所有评论。它们都可以归结为定义什么是业务规则和定义什么是授权规则。并非所有内容都应表示为授权策略。您的购物车示例非常好。事实上,您只能拥有10个项目,这绝对不是授权规则,应该保留在您的业务逻辑中。
// Aproach 1 : call the repository with the method made explicit in the domain,
// in order to check if the book with a specific author exists
class ChangeBookTitleCommandHander {
    public function handle($command) {
        $book = $bookRepository->findForAuthorIdByBookId($command->authorId, $command->bookId );

        if($book === NULL) {
            throw new CommandHandlingFailedException();
        }
    }
}

// Aproach 2 use an authorization service inside the controller to check if a user  
// has access to the specific book resource in order to change it's title
class Controller {
    public function changeTitleAction() {
        // This will use the authorizationDao->findBookOfIdForAuthorId($bookId, $authorId) to allow
        // access for changing that resource
        // @throws UnauthorizeAccessException
        $authorizationService->authorizeCommand($changeBookTitleCommand);
    }
}