建立更好的访问控制系统

时间:2010-08-13 21:20:02

标签: php frameworks user-accounts

我正在构建一个访问控制系统,作为我正在开发的Web框架的一部分。我想让它变得超级灵活和棒极了。你可以通过提供我的设计的输入和见解来帮助我吗?到目前为止,这是我的工作(我的具体问题在底部):

用户

  • 用户有一个用户名(32个字符,没有空格)和密码
  • 用户有一个或多个必须验证的电子邮件地址
  • 用户可以使用其用户名或任何电子邮件地址登录
  • 用户可能与零个或多个帐户相关联

帐户

  • 帐户代表一个或多个用户
  • 每个用户可能拥有帐户的特定权限或角色(例如,帐户所有者或“可以添加新用户”)
  • 所有帐户都与帐户类型相关联

帐户类型

  • 帐户类型包含零个或多个帐户类型角色
  • 帐户类型具有零个或多个帐户类型功能

帐户类型角色

  • 例如,“所有者”,“管理员”,“超级用户”,“访客”等
  • 帐户类型角色是帐户类型权限的集合

帐户类型权限

  • 帐户类型权限是系统中应用程序逻辑将验证的特定操作
  • 他们可以引用父级,因此可以对它们进行分层分组
  • 例如为:
    • “用户管理”
      • “添加用户”
      • “删除用户”
  • 这些权限可能专门用于帐户类型功能

帐户类型功能

  • 可以在帐户上激活帐户类型功能,以便为其提供更多权限
  • 例如,“标准帐户”或“高级帐户”
  • 如果在帐户上激活这些功能,则会为帐户所有者提供更大的系统访问权限
  • 他们在被激活或停用时被跟踪,可以定期或按需收费

问题

对用户操作进行应用程序逻辑检查的最佳方法是什么?我正在考虑将所有用户的权限存储在一个对象中进行会话(这需要注销/登录才能刷新权限,我不喜欢这些权限 - 对实时权限管理的任何想法?):

{
  "All Permissions": {
    "User Management": {
        "Add User",
        "Delete User"
    },
    "Premium Account": {
        "Download Files",
        "Upload Files"
    },
  }
}

然后我会声明系统中特定操作所需的权限。也许是这样的:

Permission::require('Add User');

如果声明的权限不在users权限对象中,则请求将失败。这对于每个用户操作来说似乎都很激烈。另外,如果另一个权限子集的字符串为“添加用户”,该怎么办?

提前感谢您对此的任何帮助!

9 个答案:

答案 0 :(得分:12)

查看您的帐户类型权限,看起来您考虑了访问控制列表(ACL)样式系统设计。

如果你想让它超级灵活和令人敬畏,那么我建议这是一个好的设计。 ACL系统的工作对于简单的权限 - 也许在您的方案中实际上是可以的 - 但是一旦授予权限的规则变得极其动态 - 即依赖于超出用户身份或角色的任何上下文数据 - ACL的下降平坦的。

This video详细介绍了ACL的失败,并讨论了实现访问控制的其他方法,以解决实际情况。

此外,之前已经完成了这项工作(尽管我们可以看到的实现很少);或许看看Rhino Security。原始链接http://ayende.com/Blog/category/548.aspx已损坏,因此请保留互联网存档链接以供参考。

答案 1 :(得分:4)

我看到的一种我喜欢的方式是一种“级联”权限。您有一组核心权限 - 比如读,写,删除 - 这些权限可以分配给组或用户。

READ    USER1
READ    USER2
WRITE   USER2
READ    USER3
WRITE   USER3
DELETE  USER3

或者,您可以指定“组”而不是用户名。

READ    SUBSCRIBER
READ    EDITOR
READ    ADMIN
WRITE   EDITOR
WRITE   ADMIN
DELETE  ADMIN
USER1   SUBSCRIBER
USER2   EDITOR
USER3   ADMIN

然后您可以简单地使用表中的值来排序和查找记录。这允许灵活地成为具有互斥权限的多个组的成员等。

答案 2 :(得分:3)

我会看一下Java系统的权限:

http://download.oracle.com/javase/6/docs/api/java/security/Permission.html

它使用“蕴涵逻辑”;也就是说,许可对象决定是否允许给定动作(即权限是否“暗示”对资源的访问)。我还会查看BasicPermission,因为它有一个非常简单的命名空间规范权限。在你的例子中,它将是(遵循CRUD命名法)

  • user.create
  • user.delete
  • file.read
  • file.create

在我们的webapp中,我们为每个可以请求的资源或过程分配权限,并为每个用户分配一组权限。然后我们做了

boolean isAuthorized = user.permissions.implies(requestedResource.permission); (暗示标准封装)

确定是否允许用户访问。

答案 3 :(得分:3)

这是我的两种感觉,值得的。

首先我想说,当你开始设计时,想一想OOP以及它如何应用于系统中的实体。用户,User_Role,角色,Role_Permissions,帐户,Account_Types,Account_Type_Features等。

用户: - 应该允许使用OpenID,因为它正在获得牵引力 - 用于在数据库可移植性的ID或UUID之间进行选择的选项

用户角色:(不是帐户类型角色)我建议您在这里非常具体。例如,您在哪里绘制高级用户和管理员之间的界限? ADMIN和OWNER有什么区别?只要这些明确定义(而不是模糊),它就会起作用。 如果您的用户群中存在任何问题,很快您就会拥有一套令人费解的角色和权限。 我会将此保持在最低限度以保持清洁。用户将弄清楚如何使用它们。 另外,我会将其更改为USER TYPE ROLES。角色应该适用于用户,而不是帐户。

角色允许:(不是帐户类型的许可) 这应该改为ROLE PERMISSIONS。权限扩展到用户角色,而不是帐户或用户。 根据我的经验,设计越清晰,在路上混淆的空间就越小。 此外,避免像瘟疫一样的ACL。使它成为简单的一对一关系。我还没有找到实施ACL的理由 适用于任何基于Web的系统。其他基于权限的系统更容易理解,维护和使用。没有任何意义 使问题复杂化。

帐户类型功能 请注意不要模糊帐户类型权限和帐户类型功能。您的第一个项目符号点使用权限一词。 将其更改为功能。帐户类型将激活更高级/高级功能(而非权限)。

权限管理: 对于在Web上运行的无状态应用程序,会话是可行的方法。优点是DB不会经常往返 检查用户是否获得授权。

Permission::require()应遵循与Sessions相同的参数定义。这将防止其他权限子集的重叠。 所以这个电话就像是Permission::require('User Management', 'Add User'); 这意味着它会寻找$_SESSION['All Permissions']['User Management']['Add User'] 这样可以防止歧义。

记住SIMPLE更好。

答案 4 :(得分:2)

Zed Shaw对ACL及其局限性有一些有趣的话要说。在你沿着这条路走下去之前绝对值得一看。

http://vimeo.com/2723800

答案 5 :(得分:2)

我建议你查看Zend Framework的Zend_Acl。像大多数Zend包一样,它有一个陡峭的学习曲线。但是,当您完全掌握资源,操作,角色关系时,它将成为您自己的ACL实现的一个多功能且强大的基础。

对现有ACL包和模式进行一些研究。

答案 6 :(得分:1)

我没有任何具体的建议,但我熟悉的两个系统具有非常好的灵活访问/许可系统,Drupal和Plone。你可能比复制它们中的任何一个更糟糕。他们背后有多年的实际测试。

答案 7 :(得分:1)

您使用的语义有点令人困惑。例如,“所有者”,“管理员”,“高级用户”,“访客”的帐户类型看起来更像“用户类型”。

此外,也许你可以将你称之为“AccountPermissions”的东西作为Account的子类。这种方式取决于帐户的类型,将适用不同的权限。

答案 8 :(得分:0)

看看这里 http://www.sqlrecipes.com/database_design/fine_grained_role_based_access_control_rbac_system-3/

这些概念基本相同,使用起来非常快,而且对于非常精细的访问控制来说非常快。