【问题标题】:Restrict access to the owner of an object in DDD限制对 DDD 中对象所有者的访问
【发布时间】:2011-12-09 15:13:51
【问题描述】:

假设有一个对象TaskList,只能由其所有者编辑和删除。其他用户应该只能接受任务并更新其状态。

我想到了以下选项:

  • 在 Web 应用程序的控制器中检查所有权和访问权限
  • 让存储库返回代理对象,该对象会在某些操作上引发异常,但控制器(或视图)仍需要知道哪些操作(以链接或表单字段的形式)应该是可见的
  • 将调用者(用户)传递给域对象的方法,以便域对象自己检查调用者是否被允许。

使用的技术是Java。

还有其他/更好的想法吗?

关于安全和 DDD 的有趣文章

我现在已经接受了我自己的答案,因为那是我实际使用的,但欢迎提出进一步的建议。

【问题讨论】:

    标签: java security domain-driven-design authorization


    【解决方案1】:

    我不会将所有权/权限模型编码到TaskList 域对象中。这种业务逻辑应该是外部的。我也不喜欢代理对象的想法。虽然它肯定会起作用,但它会混淆调试,并且至少在这种情况下会变得不必要地复杂。我也不会在控制器中检查它。

    相反,我将创建一个业务逻辑对象来监督TaskList 的权限。所以 TaskList 会有一个 owner 字段,但你会有类似的内容:

    public class TaskListAccessor {
        private TaskList taskList;
        private User reader;
    
        public void updateStatus(Status status) {
            // everyone can do this
            taskList.updateStatus(status);
        }
    
        /** Return true if delete operation is allowed else false */
        public boolean isDeleteAllowed() {
            return taskList.getOwner().equals(reader);
        }
    
        /** Delete the task.  Only owners can do this.  Returns true if worked else false */
        public boolean delete() {
            if (isDeleteAllowed()) {
               taskList.delete();
               return true;
            } else {
               return false;
            }
        }
        // ... other accessors with other is*Allowed methods
    }
    

    如果您需要要求对TaskList 对象的所有操作都通过访问器,那么您可以创建一个工厂类,它是唯一使用包构造函数或其他东西创建TaskList 的工厂类。也许工厂是唯一会使用 DAO 从数据存储中查找TaskList 的人。

    但是,如果以这种方式控制的方法太多,那么代理可能会更容易。在这两种情况下,都建议使用TaskList 作为接口,实现类被代理或访问器隐藏。

    【讨论】:

      【解决方案2】:

      我发现按照“Gray”的建议为每个受保护的域类创建访问器类不必要地复杂。我的解决方案可能并不完美,但易于使用并且——更重要的是——健壮。您不能忘记使用某个对象或检查外部条件。

      public class TaskList {
      
          private SystemUser owner;
          private List<Task> tasks = new ArrayList<>();
      
          public TastList(SystemUser owner) {
              this.owner = owner;
          }
      
          public void Add(Task task) {
              Guard.allowFor(owner); 
              tasks.add(task);
          }
      }
      

      Guard 知道当前用户(例如来自本地线程)并将其与作为参数传递给allowFor(owner) 的所有者进行比较。如果访问被拒绝,则会引发安全异常。

      这很简单、健壮,甚至易于维护,因为如果底层身份验证发生变化,只需更改保护。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-06-07
        • 1970-01-01
        • 2011-03-09
        • 1970-01-01
        • 1970-01-01
        • 2017-05-09
        • 1970-01-01
        • 2013-08-30
        相关资源
        最近更新 更多