【问题标题】:Should authorization be part of the model or controller?授权应该是模型或控制器的一部分吗?
【发布时间】:2011-11-07 20:33:27
【问题描述】:

我正在编写一个具有一些 ACL 要求的 Web 应用程序:用户可以更改某些项目,某些项目可能由多个用户编辑,管理员可以编辑任何内容,而经理可以编辑她组织内的所有内容等。

我正在使用 Play!框架,从Secure 模块的外观来看,似乎将授权问题放在控制器中。但是,在我看来,授权问题是业务逻辑的一部分,因此应该在模型中。此外,我开始在需要重构的控制器中看到重复的逻辑。

另一方面,向模型添加授权意味着我必须通过某种方式从模型中获取当前用户,这似乎不正确。或者,我可以为每个模型方法添加一个“current_user”参数,但这似乎更糟。

那么常见的做法是什么?我可以/应该将授权码放在模型中,还是保留在控制器中?

【问题讨论】:

    标签: model-view-controller authorization playframework


    【解决方案1】:

    我认为这是一个灰色地带。有人可能会争辩说,用户访问是 HTTP 世界和面向对象世界之间映射的一部分。这就是控制器的目的(因此大量使用静态),转换传入的请求,准备处理域模型上的业务规则。

    我建议控制器逻辑绝对是控制对模型的访问的正确位置,特别是因为这主要在注释级别进行管理,并且身份验证被抽象为安全类。

    【讨论】:

    • 在我看来,我认为这是绝对正确的,但是,这是一个灰色地带,因此可以解释。所以,这取决于你是否同意我的解释:o)
    【解决方案2】:

    授权不应成为控制器或域模型的一部分。

    相反,它应该在服务层中。

    控制器应该只是充当 HTTP 和应用程序服务之间的调度程序和委托。 它是发生编排的应用程序服务。这是放置授权的最佳位置。

    假设用户 A 被授权访问域 X 中的数据,但无权访问域 Y 中的数据。如果授权被放置在控制器中,那么用户 A 在控制器 X 中获得授权,并且通过服务调用可以访问来自域 Y 的数据,这不是我们所期望的。

    由于领域模型在服务层相互通信,因此最好将授权放在同一级别。

    【讨论】:

    • 所以,如果有一个逻辑超级管理员可以访问所有资源,而管理员可以访问一些资源,那么这个逻辑在哪里:控制器(给定这样的逻辑可以通过基于策略的授权来处理反过来使用httpcontext。我不希望在服务中使用httpcontext。),服务或域模型
    • 对此的另一个副作用,控制器可能不是您服务的唯一入口点,如果我突然想要 gRPC 端点和 1 个 gRPC 端点将所有内容映射到服务怎么办,与 websockets 一样,控制器应该仅将请求转换为域对象,一旦它传入内部,服务会处理所有事情,这样您可以稍后在需要时升级您的端点。
    【解决方案3】:

    在大多数情况下,安全性应该在模型之上一层(或多层)。安全性是一个独立的域,限制对较低层的访问。

    我认为安全性不应该在控制器级别完成。

    在我看来,这应该是这样的:

    视图 -> 控制器 -> 安全 -> 模型

    安全层可以是模型的外观或代理,保护访问,但对控制器透明。

    但是,如果要根据用户的访问权限修改视图,则可能必须在控制器级别进行一些检查(例如在 ViewModel 上设置 CanEdit 布尔属性的值)。

    【讨论】:

    • 您混淆了安全性和授权。必须在应用程序的每一层处理安全问题 - 请参阅:深度防御。问题是“授权属于哪里?”,而不是安全性。
    【解决方案4】:

    我个人非常喜欢 Play 的方式!安全模块处理此问题 (the tutorial is ever-helpful here)。如果您不介意使用 @Before 注释,它非常轻松。

    【讨论】:

      【解决方案5】:

      我正处于这个阶段,并打算通过以下方式处理:

      • 不通过 JS 进行表单验证,而是通过 HTTPS ajax

      • 一个 Ajax php 类

      • 将表单数据发送到模型作为其具体验证的数据
        常见类型,例如电子邮件和密码(可能关联数组验证将被其他类重用,因此这绝对是一个模型区域)。

      • 如果没有错误,则在用户表中查找凭据电子邮件 /
        使用身份验证传递给控制器​​的密码凭据
        登录/注册/密码重置等类型

      • 控制器然后生成所需的输出视图或设置用户登录会话等

      这是基于 Laravel 的,但我有自己的库,希望它独立于 laravel 并且只是松散地基于这一重要要求。

      关键是模型将所需的凭据作为数据查找,然后发送给控制器,因为它不关心应该如何处理它。我认为这是使这个领域成为每个组件之间明确责任的唯一方法。

      【讨论】:

        【解决方案6】:

        根据我对 MVC 框架的个人经验,我想说:

        1. Model 是一个对象,表示它应该是的数据库表 纯粹的,不应包含任何额外的逻辑。
        2. 控制器是做出决定和其他 自定义逻辑,所以授权应该在控制器中。它 可以设计一些钩子来检查用户是否被授权 或者不在所有需要的地方,所以你不会有代码重复 DRY。

        3. 如果您使用的是典型的 REST架构是制作一个令牌,将其保存在数据库中 客户端并在每个请求上验证此令牌。如果您正在使用 Web 浏览器应用程序,您可以使用服务器端会话进行授权( 它更容易)。

        所以我的建议是将授权逻辑保留在Controller中。

        【讨论】:

        • 所以,如果有一个逻辑超级管理员可以访问所有资源,而管理员可以访问某些资源,那么这个逻辑在哪里:控制器(授权)、服务或域模型
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-22
        • 2013-12-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多