授权应该是模型或控制器的一部分吗?
我正在编写一个具有一些 ACL 要求的 Web 应用程序:用户可以更改某些项目,某些项目可以由多个用户编辑,管理员可以编辑任何内容,经理可以编辑其组织内的所有内容等。
我正在使用玩!框架,并且从 Secure
模块的外观来看,放置授权问题的地方似乎是在控制器中。然而,在我看来,授权问题是业务逻辑的一部分,因此应该在模型中。此外,我开始在控制器中看到需要重构的重复逻辑。
另一方面,向模型添加授权意味着我必须有某种方法从模型中获取当前用户,这似乎不对。或者,我可以向每个模型方法添加一个“current_user”参数,但这似乎更糟糕。
那么常见的做法是什么呢?我可以/应该将授权代码放入模型中,还是将其保留在控制器中?
I'm writing a web application with some ACL requirements: a user can make changes to some items, some items may be editable by several users, administrator can edit anything and a manager can edit everything within her organization etc.
I'm using the Play! framework, and by the looks of the Secure
module, it seems that the place to put authorization concerns is in the Controllers. However, it seems to me that the authorization issues are part of the business logic, and therefore should be in the model. Furthermore, I'm starting to see duplicated logic in the controllers that I need to refactor out.
On the other hand, adding authorization to the model means that I'd have to have some way of getting the current user from within the model, which doesn't seem right. Alternatively, I could add a "current_user" parameter to every model method, but that seems even worse.
So what is the common practice? Can/should I put authorization code in the model, or keep it in the controller?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
授权不应成为控制器或域模型的一部分。
相反,它应该位于服务层。
控制器应该只充当 HTTP 和应用程序服务之间的调度程序和委托。
这是进行编排的应用程序服务。这是放置授权的最佳位置。
假设用户 A 被授权访问域 X 中的数据,但没有被授权对域 Y 中的数据进行读取访问。如果将授权置于控制器中,则用户 A 在控制器 X 中获得授权,并且通过服务调用可以从域 Y 访问数据,这不是我们所期望的。
由于领域模型在服务层上相互通信,因此最好将授权放在同一级别。
Authorization should neither be part of controller or domain model.
Instead it should be in the service layer.
Controller should just act as dispatcher and delegate between HTTP and application service.
It's the application service where the orchestration takes place. This is the best place for placing authorization.
Suppose user A is authorized to access data from domain X, but not authorized for even a read access for data from domain Y. If authorization is placed in the controller, then user A gets authorized in the controller X, and via the service calls can access data from domain Y, which is not what we expected.
Since domain models communicate with each other on service layer, hence it best to place the authorization on the same level.
我认为这是一个灰色地带。有人可能会说,用户访问是 HTTP 世界和面向对象世界之间映射的一部分。这就是控制器的目的(因此大量使用静态),转换传入的请求,准备处理域模型上的业务规则。
我建议控制器逻辑绝对是控制模型访问的正确位置,特别是因为这主要在注释级别进行管理,并且身份验证被抽象到安全类。
I think this is a grey area. One could argue that the user access is part of the mapping between the HTTP world and the Object-Oriented world. This is what the controller is intended for (hence the heavy use of statics), to transform the incoming request, ready to process the business rules on the domain model.
I would suggest that the controller logic is absolutely the right place for controlling the access to the model, especially as this is managed largely at an annotation level, and the authentication is abstracted off to a Security class.
在大多数情况下,安全性应该位于模型之上的一层(或多层)。安全性是一个独立的域,限制对较低级别的访问。
我认为安全性不应该在控制器级别完成。
在我看来,这应该是这样的:
查看 ->控制器->安全->模型
安全层可以是模型的外观或代理,保护访问,但对控制器是透明的。
但是,如果要根据用户的访问权限修改视图,则可能必须在控制器级别进行一些检查(例如在 ViewModel 上设置 CanEdit 布尔属性的值)。
In most cases, the security should be one (or more) layer above the Model. Security is a domain on it's own, restricting access to a lower level layer.
I don't think the security should be done at the controller level.
In my opinion, this should look like that:
View -> Controller -> Security -> Model
The security layer could be a façade or a proxy over the model, protecting access, but be transparent to the controller.
However, if the views are to be modified depending on the access rights of the user, some checks might have to happen at the controller level (like setting the value of a CanEdit boolean property on the ViewModel).
我个人非常喜欢Play!安全模块可以处理这个问题(教程在这里非常有帮助)。如果您不介意使用
@Before
注释,那么这非常简单。I personally really like the way the Play! Secure module handles this (the tutorial is ever-helpful here). If you don't mind using the
@Before
annotation, it's pretty painless.我现阶段打算按以下方式处理此问题:
没有 JS 的表单验证,而是通过 HTTPS ajax
一个 Ajax php 类< /p>
将表单数据发送到模型作为其具体验证的数据
常见类型,例如电子邮件和密码(可能关联数组验证将被其他类重用,因此这肯定是一个模型区域)。
如果没有错误,则在用户表中查找凭据电子邮件 /
通过身份验证将密码凭据传递给控制器
键入例如登录/注册/密码重置
控制器然后生成所需的输出视图或设置用户登录会话等
这是基于Laravel,但我有自己的库,因为希望它独立于 Laravel,并且只是松散地满足这一重要需求。
要点是模型将所需的凭据作为数据查找,然后发送到控制器,因为它不关心如何处理它。我认为这是使该领域成为每个组件之间明确责任的唯一方法。
I am at this stage and intending to handle this in the following way:
No form validation by JS, instead via HTTPS ajax
An Ajax php class
Form data sent to a model as its data for concrete validation for
common type such as email and password (likely assoc array validation will be reused by other classes so this is definately a model area).
if no error a lookup in a User table for the credentials email /
password credentials passed to a Controller with the authentication
type such as login / signup / password reset
the controller then produces the required output view or sets user logged in session etc
This is based in Laravel but I have my own library as want it independent of laravel and just loosely based for this vital requirement.
The point being that the Model looks up the required credentials as data, then sends to the Controller as it does not care how it should be processed. I think this is the only way to make this area a definitive responsibility between each of the components.
根据我个人使用 MVC 框架的经验,我会说:
纯粹的,不应该包含任何额外的逻辑。
控制者是做出决定和其他决定的地方
自定义逻辑,因此授权应该在控制器中。它
可以设计一些钩子来检查用户是否被授权
或者不在所有需要的地方,这样你就不会重复代码。
如果您使用的是典型的,向用户授予权限的最佳方式
REST架构是制作一个令牌,将其保存在数据库中并在
客户端并在每个请求上验证此令牌。如果您正在使用
Web 浏览器应用程序您可以使用服务器端会话进行授权(
它更容易)。
所以我的建议是将授权逻辑保留在控制器中。
From my personal experience with MVC frameworks I would say:
pure and should not contain any additional logic.
Controller is the place where are made the decisions and other
custom logic, so the authorization should be in the controller. It
could be designed some hook that can check if the user is authorized
or not in all needed places so you wont have a code repetition DRY.
The best way to give permission to user if you are using a typical
REST architecture is to make a token , save it in the databse and on
client side and verify this token on every request. If you are using
web browser app you can use server-side sessions for authorization (
Its much more easier).
So my propose is to keep the authorization logic in the Controller.
我将使用 Rails 作为示例。授权库 pundit 将授权牢固地置于“模型”域内 - 这是通过其帮助程序强制执行的方法。
假设您有一个
ShoppingBag
模型。您可能想要创建
一个 ShoppingBag如果您在模型和控制器之间有 1-1 映射,那么它会非常有效。但是,如果您需要同一型号的第二个控制器怎么办?现在你被困住了!
正是因为这个原因,我不喜欢专家和康康康。对我来说,控制器级别的授权是理想的。在模型级别上这样做对我的限制太大,没有任何相应的增益。
I'll use Rails as an example. The authorization library, pundit, places authorization firmly within the "model" domain - this is enforced through their helper methods.
Suppose you have a
ShoppingBag
model. You might want tocreate
a ShoppingBagIt works really well if you have a 1-1 mapping between a model and a controller. But what if you need a second controller on the same model? Now you're stuck!
It's for that reason I dislike pundit, and CanCanCan. Authorization at the controller level, for me, is ideal. Doing so on the model level limits me too much, without any commensurate gain.