授权是否应该是模型或控制器的一部分?

时间:2011-08-31 18:16:01

标签: model-view-controller authorization playframework

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

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

另一方面,向模型添加授权意味着我必须有一些方法从模型中获取当前用户,这似乎不对。或者,我可以为每个模型方法添加“current_user”参数,但这看起来更糟。

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

6 个答案:

答案 0 :(得分:16)

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

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

答案 1 :(得分:6)

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

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

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

查看 - >控制器 - >安全 - >模型

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

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

答案 2 :(得分:4)

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

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

Controller应该充当HTTP和应用程序服务之间的调度程序和委托。 它是编排发生的应用程序服务。这是授权的最佳场所。

假设用户A有权从域X访问数据,但未授权对域Y的数据进行读访问。如果授权存放在控制器中,则用户A在控制器X中获得授权,并通过服务调用可以访问域Y的数据,这不是我们所期望的。

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

答案 3 :(得分:1)

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

答案 4 :(得分:1)

我现在正处于这个阶段,并打算以下列方式解决这个问题:

  • JS没有表单验证,而是通过HTTPS ajax

  • Ajax php类

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

  • 如果在用户表中没有错误查找凭据电子邮件/
    密码凭证通过身份验证传递给Controller 类型如登录/注册/密码重置

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

这是基于Laravel,但我有自己的图书馆,因为它希望它独立于laravel并且松散地基于这个至关重要的要求。

关键是模型将所需的凭据作为数据查找,然后发送到Controller,因为它不关心应该如何处理它。我认为这是使这个领域成为每个组成部分之间最终责任的唯一方法。

答案 5 :(得分:1)

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

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

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

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