访问控制设计模式

发布于 2024-08-15 08:15:05 字数 808 浏览 10 评论 0 原文

我正在开发一个 PHP 应用程序,我想为我的一些对象添加访问控制。我没有将这个问题标记为 PHP,因为我觉得这个问题不是特定于语言的。

假设我有一个“服务类”,

abstract class Service {


}

许多服务都使用它作为基类。一个伪示例是:

class Companies extends Service {

  function getCompanyInfo($id) {
      //...
  }

}

稍后我想添加访问控制。示例“getCompanyInfoById”方法是“读取”操作,因此这需要“读取”权限。

此时我可以通过以下方式实现这一点:

  1. 将访问控制添加到 Service 类。每个方法(例如 getCompanyInfoById)必须在内部调用“hasPrivilege”方法才能完成操作并返回结果。
  2. 将所有 Service 对象包装在某种 Proxy 对象中,该对象将在调用内部对象中的方法之前检查权限。
  3. 完全分离访问控制,并强制“调用者”在调用方法之前检查权限。

每个选项的缺点:

  1. 这需要更改所有服务, 并要求他们意识到 访问控制。我觉得这样 反对关注点分离。
  2. 这破坏了 OOP 功能,例如 多态性。来电者不再 知道任何服务的接口 支持。
  3. 这是最灵活的,但最大的缺点是检查权限现在是隐式的。开发人员可能会“忘记”,或者复杂的代码路径可能会导致调用未经授权的服务。

有没有更好的方法来解决这个问题?

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:

  1. 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.
  2. Wrap all Service objects in a some kind of Proxy object that will checks privileges before calling the method in the inner-object.
  3. Completely separate access control, and force the 'caller' to check privileges before calling the method.

Cons for every option:

  1. This requires changing all Services,
    and requires them to be aware of
    Access control. I feel this goes
    against Separation of concerns.
  2. This breaks OOP features, such as
    Polymorphism. The caller no longer
    knows what interfaces any service
    supports.
  3. 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?

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

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

发布评论

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

评论(3

青萝楚歌 2024-08-22 08:15:05

另一个解决方案可能是您的 1.ex 的一个小变体

class Service
{
  var $ACL = //some hash map with acl
}

class Companies extends Service
{

  function getCompanyById($id)
  {
    //real code
  }
}

class SafeCompanies extends Companies
{
//If a method must be "protected" with an ACL, you must override them in this way
  function getCompanyById($id)
  {
    $this->check('read'); //raise an exception if current user haven't READ privilege
    parent::getCompanyById($id);    
  }  
} 

这样你就不会混合职责,并且仍然可以使用多态性,

我的 2 美分

Another solution could be a little variant of your 1.

ex.

class Service
{
  var $ACL = //some hash map with acl
}

class Companies extends Service
{

  function getCompanyById($id)
  {
    //real code
  }
}

class SafeCompanies extends Companies
{
//If a method must be "protected" with an ACL, you must override them in this way
  function getCompanyById($id)
  {
    $this->check('read'); //raise an exception if current user haven't READ privilege
    parent::getCompanyById($id);    
  }  
} 

in this way you dont mix responsibilities and still can use polymorphism

my 2 cents

万劫不复 2024-08-22 08:15:05

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.

悍妇囚夫 2024-08-22 08:15:05

十年后......世界已经发生了很大的变化,特别是出现了一种全新的范式:外部化授权。公平地说,每个开发框架都有自己的版本(例如 Ruby 中的 CanCanCan 或 Java 中的 Spring Security 或 C# 中基于声明的授权)。外部化授权旨在将授权逻辑与业务逻辑解耦。这个想法是授权需求可能独立于业务逻辑而发展。例如,您的业务逻辑提供对银行帐户的访问(查看/编辑/删除/转移)。该功能是稳定的 - 在不久的将来不会改变。然而,授权需求可能会因立法(GDPR、开放银行...)或不同的要求(委托、父子、VIP...)而发生变化,这就是您想要外部维护授权的原因。

为此,有一个名为基于属性的访问控制的模型(),它是更知名的基于角色的访问控制()。在 RBAC 中,访问控制是以身份为中心的。它基于用户、角色以及用户所属的组。很多时候这还不够。在ABAC中,您可以使用用户、资源、上下文(时间)和操作的属性。 ABAC 还允许您使用标准化策略语言以简单的古英语编写策略 ( 或 Rego)。云平台(AWS 和 Google)也实现了自己的语言(分别称为 Google IAM 和 AWS IAM)。

ABAC 的一些好处包括:

  • 灵活性:您可以更改授权策略,而无需触及应用程序/API
  • 可重用性:您可以将相同的策略应用于数据、API、应用程序或基础设施。
  • 可见性:将授权明确表示为策略,而不是硬编码逻辑,这意味着您可以轻松审核策略并了解什么是可能的/什么不是可
  • 审核性:使用 ABAC,您可以获得所有已授予或拒绝的访问的单个日志。

如果您想了解更多信息,请查看 Wikipedia 页面的 ABACALFA 以及 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 () which is an evolution / extension to the more well-known role-based access control (). 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 ( or 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:

  • flexibility: you can change your authorization policies without touching your apps / APIs
  • reusability: you can apply the same policies to data, APIs, apps, or infrastructure.
  • visibility: express authorization as policies rather than hard-code the logic which means you can easily audit the policies and understand what is possible / what isn't
  • auditability: with ABAC you get a single log of all access that was granted or denied.

If you want to learn more, check out the Wikipedia pages for ABAC and ALFA as well as NIST's page on ABAC.

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