我正在开发一个 PHP 应用程序,我想为我的一些对象添加访问控制。我没有将这个问题标记为 PHP,因为我觉得这个问题不是特定于语言的。
假设我有一个“服务类”,
abstract class Service {
}
许多服务都使用它作为基类。一个伪示例是:
class Companies extends Service {
function getCompanyInfo($id) {
//...
}
}
稍后我想添加访问控制。示例“getCompanyInfoById”方法是“读取”操作,因此这需要“读取”权限。
此时我可以通过以下方式实现这一点:
- 将访问控制添加到 Service 类。每个方法(例如 getCompanyInfoById)必须在内部调用“hasPrivilege”方法才能完成操作并返回结果。
- 将所有 Service 对象包装在某种 Proxy 对象中,该对象将在调用内部对象中的方法之前检查权限。
- 完全分离访问控制,并强制“调用者”在调用方法之前检查权限。
每个选项的缺点:
- 这需要更改所有服务,
并要求他们意识到
访问控制。我觉得这样
反对关注点分离。
- 这破坏了 OOP 功能,例如
多态性。来电者不再
知道任何服务的接口
支持。
- 这是最灵活的,但最大的缺点是检查权限现在是隐式的。开发人员可能会“忘记”,或者复杂的代码路径可能会导致调用未经授权的服务。
有没有更好的方法来解决这个问题?
I'm working on a PHP application, and I'd like to add access control to some of my objects. I didn't tag this question as PHP, as I feel this question is not language specific.
Say I have a 'Service class'
abstract class Service {
}
Many services use this as a baseclass. One pseudo example would be:
class Companies extends Service {
function getCompanyInfo($id) {
//...
}
}
Later down the road I want to add access control. The example 'getCompanyInfoById' method is a 'read' operation, so this would require a 'read' privilege.
At this point I can implement this in the following way:
- Add accesscontrol to the Service class. Every method (such as getCompanyInfoById) must call the 'hasPrivilege' method internally before completing the operation and returning the result.
- Wrap all Service objects in a some kind of Proxy object that will checks privileges before calling the method in the inner-object.
- Completely separate access control, and force the 'caller' to check privileges before calling the method.
Cons for every option:
- This requires changing all Services,
and requires them to be aware of
Access control. I feel this goes
against Separation of concerns.
- This breaks OOP features, such as
Polymorphism. The caller no longer
knows what interfaces any service
supports.
- This is the most flexible, but the big drawback is that checking permission is now implicit. Developers can 'forget' or complex codepaths can cause unauthorized services to be called.
Are there better ways to approach this altogether?
发布评论
评论(3)
另一个解决方案可能是您的 1.ex 的一个小变体
。
这样你就不会混合职责,并且仍然可以使用多态性,
我的 2 美分
Another solution could be a little variant of your 1.
ex.
in this way you dont mix responsibilities and still can use polymorphism
my 2 cents
Java EE 模型几乎与 2 类似。您的代码在“容器”中运行,您向容器告知您的接口入口点(servlet 的 URL、EJB 的方法)并定义可以使用这些入口点的角色。管理员将身份验证信息(例如 LDAP 用户和组)映射到特定角色,容器在授予对入口点的访问权限时参考该映射。
这里的关键是容器“知道”你的代码,它实际上是一个非常聪明的代理。
在没有容器的情况下,我会考虑代理方法,也许使用某种面向方面的技术。
我认为你是对的,选项 3 非常脆弱,客户端程序员的责任太多。
The Java EE model is pretty much on the lines of 2. Your code runs in a "Container", you tell the container about your interface entry points (URLs for servlets, methods for EJBs) and define the roles that can use these entry points. An adminstrator maps the authentication info (eg. LDAP user and groups) to specific roles and the container consults that mapping in granting access to the entry points.
The key here is that the Container "knows" about your code, it's effectively a quite clever proxy.
In the absence of a container I'd be looking at the proxy approach, perhaps using some kind of Aspect Oriented technique.
I think you're right that option 3 is very brittle,too much responsibility on the client programmers.
十年后......世界已经发生了很大的变化,特别是出现了一种全新的范式:外部化授权。公平地说,每个开发框架都有自己的版本(例如 Ruby 中的 CanCanCan 或 Java 中的 Spring Security 或 C# 中基于声明的授权)。外部化授权旨在将授权逻辑与业务逻辑解耦。这个想法是授权需求可能独立于业务逻辑而发展。例如,您的业务逻辑提供对银行帐户的访问(查看/编辑/删除/转移)。该功能是稳定的 - 在不久的将来不会改变。然而,授权需求可能会因立法(GDPR、开放银行...)或不同的要求(委托、父子、VIP...)而发生变化,这就是您想要外部维护授权的原因。
为此,有一个名为基于属性的访问控制的模型(abac),它是更知名的基于角色的访问控制(rbac)。在 RBAC 中,访问控制是以身份为中心的。它基于用户、角色以及用户所属的组。很多时候这还不够。在ABAC中,您可以使用用户、资源、上下文(时间)和操作的属性。 ABAC 还允许您使用标准化策略语言以简单的古英语编写策略 ( xacml 或 alfa 或 Rego)。云平台(AWS 和 Google)也实现了自己的语言(分别称为 Google IAM 和 AWS IAM)。
ABAC 的一些好处包括:
如果您想了解更多信息,请查看 Wikipedia 页面的 ABAC 和 ALFA 以及 NIST 关于 ABAC 的页面。
Ten years later... The world has evolved quite a bit since and in particular a whole new paradigm has come up: externalized authorization. To be fair, each and every development framework has its own version of it (e.g. CanCanCan in Ruby or Spring Security in Java or Claims-based authorization in C#). Externalized authorization aims to decouple authorization logic from business logic. The idea is that authorization needs might evolve independently of business logic. For instance your business logic provides access to bank accounts (view / edit / delete / transfer). The functionality is stable - it won't change in the near future. However, the authorization needs might evolve because of legislation (GDPR, Open Banking...) or different requirements (delegation, parent-child, VIP...) This is why you want to maintain authorization externally.
To do so, there is a model called attribute-based access control (abac) which is an evolution / extension to the more well-known role-based access control (rbac). In RBAC, access control is identity-centric. It is based on the user, the role, and the group(s) the user belongs to. That's not enough often times. In ABAC, you can use attributes of the user, resource, context (time), and action. ABAC also lets you write policies in plain old English using standardized policy languages (xacml or alfa or Rego). The cloud platforms (AWS and Google) have also implemented their own language (Called Google IAM and AWS IAM respectively).
Some of the benefits of ABAC are:
If you want to learn more, check out the Wikipedia pages for ABAC and ALFA as well as NIST's page on ABAC.