限制对 DDD 中对象所有者的访问

发布于 2024-12-20 13:11:41 字数 672 浏览 3 评论 0 原文

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

我想到了以下选项:

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

使用的技术是Java。

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

有关安全和 DDD 的有趣文章

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

Let's say there is an object TaskList which can be edited and deleted only by its owner. Other users should only by able to take a task and update its status.

The following options come to my mind:

  • check the ownership and access in the controller of the web application
  • let the repository return proxy object which throws exception on certain operations, but the controller (or view) would still need to know which actions (in form of links or form fields) should be visible
  • pass the caller (user) to the method of the domain object, so that the domain object can itself check whether the caller ist allowed or not.

The used technology is Java.

Any other/better ideas?

Interesting articles about security and DDD

I have accepted my own answer now, because that is what I actually use, but further suggestions are welcome.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

又怨 2024-12-27 13:11:41

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

相反,我会创建一个业务逻辑对象来监督 TaskList 的权限。因此,TaskList 将有一个所有者字段,但您将有一个执行业务逻辑的外部访问器。类似于:

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 设为接口,并由代理或访问器隐藏实现类。

I would not encode the ownership/permissions model into the TaskList domain object. That sort of business logic should be external. I also don't like the idea of a proxy object. Although it would certainly work, it would confuse debugging and is, in this case at least, unnecessarily complex. I would also not check it in the controller.

Instead I would create a business logic object which oversees the permissions for TaskList. So the TaskList would have an owner field but you would have at external accessor which would do the business logic. Something like:

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
}

If you need to require that all operations on TaskList objects go through accessors then you could create a factory class which is the only one who creates TaskList using package constructors or something. Maybe the factory is the only one who would use the DAO to look up the TaskList from the data store.

However, if there are too many methods to control in this fashion then a proxy might be easier. In both cases having TaskList be an interface would be recommended, with the implementation class hidden by the proxy or the accessor.

旧人 2024-12-27 13:11:41

我发现按照“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) 的所有者进行比较。如果访问被拒绝,将引发安全异常。

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

I found it unnecessarily complex to create accessor classes for each protected domain class as suggested by 'Gray'. My solution is probably not perfect, but simple to use and - more important - robust. You cannot forget to use a certain object or to check conditions outside.

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

The Guard knows the current user (from a thread local for example) and compares it to the owner passed as parameter to allowFor(owner). If access is denied a security exception will be thrown.

That is simple, robust and even easy to maintain since only the guard has to be changed if the underlying authentication changes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文