【问题标题】:Should one design permissions for changing the domain inside or outside of it?应该为更改域内部或外部的域设计权限吗?
【发布时间】:2014-06-17 21:23:53
【问题描述】:

以下是域类:

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) {}
}  

这是我在某些地方看到的 2 个方法,不知道哪个更好,哪个被认为是好的做法(这只是一个幼稚的例子,主要问题是放置此类授权的位置):

// 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);
    }
}

那么如何设计这种权限检查(授权)呢?在允许 BookAR 更改其状态之前,如果特定作者是该书的所有者,如何设计验证(对于不需要查询权限的 CQRS,只需状态更改权限)?

【问题讨论】:

    标签: design-patterns authorization domain-driven-design cqrs


    【解决方案1】:

    简答:

    您应该将业务逻辑与授权逻辑分开。 为什么?成功了:

    • 更易于维护
    • 更容易发展和更新
    • 更容易运行关于用户可以在系统中执行的操作的审计报告。

    长答案:

    我已经围绕这个话题在 Stack Overflow 上提供了一些答案:

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

    • 您应该避免实现自定义代码来获得授权。
    • 您应该清楚地将业务逻辑与授权逻辑分开。

    现有的授权模型 (RBAC...) 过于以用户为中心,不会让您做自己想做的事。您需要在图书所有者和试图对图书采取行动的用户之间建立关系。

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

    • 当且仅当 book.owner==user.id 时,用户才能编辑图书的元数据

    NIST 最近在 ABAC 上发布了 report,我建议您查看。 XACML,可扩展访问控制标记语言,是 ABAC 的事实上的实现。 XACML 定义:

    • 架构,
    • 一种策略语言,以及
    • 请求/响应方案。

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

    【讨论】:

    • 我不喜欢使您在域外层中泄漏业务逻辑的授权模式。当我在 CQRS 上下文中使用 DDD 时,这些授权策略中的大多数将在域模型中实现:Author->createAuthor->generateAuthorIdFromUser(){ if(!User.isActive() throw DomainException ...)}。大多数授权规则实际上是业务规则。实际授权是允许用户访问资源的授权,如果它是所有者或权限是由管理员授予的。
    • 另一个例子是购物车。可能有一条业务规则规定没有人可以将超过 10 件商品添加到购物车,但任何人都可以将商品添加到购物车。这是由业务表示的限制,与 User.isActive() 域描述相同。所以基本上任何人都可以访问 addItemToCart() 命令,但如果购物车中已经有 10 件商品,则应该无法填写此命令(因此它甚至不应该在 UI 中可用)。至于 CQRS,这应该在域中表示,并且您在应用程序的读取/查询端(资源访问)中的身份验证类型。
    • 我也同意 ABAC 比 RBAC 更好,但这当然取决于业务/应用程序的需求。我不相信 ABAC,因为它可能会从域模型 (DDD) 中泄露一些业务规则。 ABAC 似乎从域层(DDD/CQRS)中取出了大部分业务规则。我认为 ABAC 适合应用程序的查询端,而不是写入/命令端,大多数规则(如果不是全部)都将位于域层中。
    • P.S.另一个注意事项:如果 ShoppingCart 有超过 10 个产品处于无效状态(域业务规则拒绝 addItemCommand),如果 User.isNotActive() 域将拒绝从尚未完成付款的人(用户)创建新作者(即活动域描述)。这些都是领域业务规则而不是授权规则。这些规则允许或拒绝某些命令来修改域的状态。如果我用 ABAC 正确阅读,这些规则将位于域外的 Ahtorization 层中,这似乎与 DDD 规则相矛盾。
    • 我同意你所有的 cmets。它们都归结为定义什么是业务规则和定义什么是授权规则。并非所有内容都应表示为授权策略。您的购物车示例非常好。您只能拥有 10 个项目的事实绝对不是授权规则,应该保留在您的业务逻辑中。
    猜你喜欢
    • 1970-01-01
    • 2023-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多