19

我正在构建访问控制系统,作为我正在开发的 Web 框架的一部分。我想让它变得超级灵活和令人敬畏。你能通过提供关于我的设计的意见和见解来帮助我吗?这是我到目前为止的工作(我的具体问题在底部):

用户

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

账户

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

账户类型

  • 帐户类型具有零个或多个帐户类型角色
  • 帐户类型具有零个或多个帐户类型特征

帐户类型角色

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

帐户类型权限

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

帐户类型功能

  • 可以在帐户上激活帐户类型功能以赋予其更多权限
  • 例如,“标准帐户”或“高级帐户”
  • 如果在帐户上激活这些功能,将赋予帐户所有者更大的系统访问权限
  • 它们在激活或停用时被跟踪,并且可以定期或按需计费

问题

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

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

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

Permission::require('Add User');

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

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

4

9 回答 9

12

查看您的帐户类型权限,您似乎想到了访问控制列表 (ACL) 样式的系统设计。

如果你想让它变得超级灵活和令人敬畏,那么我建议这不是一个好的设计。ACL 系统对简单权限的工作——也许在你的场景中这实际上是可以的——但是一旦授予权限的规则变得哪怕是一点点动态——也就是说,依赖于用户身份或角色之外的任何上下文数据——ACL 就会失败平快。

该视频详细介绍了 ACL 的失败,并讨论了实施针对实际情况的访问控制的替代方法。

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

于 2010-08-13T21:57:30.183 回答
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

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

于 2010-08-13T21:25:11.673 回答
3

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

首先我想说,当你开始设计这个时,想想 OOP 以及它将如何应用于系统内的实体。用户、User_Role、Roles、Role_Permissions、Accounts、Account_Types、Account_Type_Features 等。

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

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

角色权限:(不是帐户类型权限)这应该更改为角色权限。权限扩展到用户角色,而不是帐户或用户。根据我的经验,设计越清晰,未来的混乱空间就越小。另外,避免像瘟疫一样的 ACL。使其成为简单的一对一关系。我还没有找到为任何基于 Web 的系统实施 ACL 的理由。其他基于权限的系统更容易理解、维护和使用。把事情复杂化是没有意义的。

帐户类型功能: 注意不要混淆帐户类型权限和帐户类型功能。您的第一个要点使用了权限一词。将其更改为功能。帐户类型将激活更多高级/高级功能(不是权限)。

权限管理: 对于在 Web 上运行的无状态应用程序,会话是必经之路。优点是无需往返数据库以不断检查用户是否被授权。

Permission::require()应该遵循与会话相同的参数定义。这将防止其他权限子集的重叠。所以调用将类似于Permission::require('User Management', 'Add User'); This 表示它会查找$_SESSION['All Permissions']['User Management']['Add User'] This will prevent ambiguity。

记住简单就是更好。

于 2010-08-18T03:54:53.923 回答
3

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

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

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

  • 用户创建
  • 用户删除
  • 文件读取
  • 文件.创建

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

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

确定是否允许用户访问。

于 2010-08-14T04:13:34.610 回答
2

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

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

于 2010-08-19T22:01:20.747 回答
2

Zed Shaw 对 ACL 及其局限性有一些有趣的看法。在您沿着这条路线走得更远之前绝对值得一看。

http://vimeo.com/2723800

于 2010-08-14T23:27:30.977 回答
1

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

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

于 2010-08-17T20:37:44.017 回答
1

我没有任何具体建议,但我熟悉的两个具有非常好的灵活访问/权限系统的系统是 Drupal 和 Plone。你可以做得比复制它们中的任何一个的工作方式更糟糕。他们已经进行了多年的实际测试。

于 2010-08-13T22:09:24.950 回答
0

Have a look here http://www.sqlrecipes.com/database_design/fine_grained_role_based_access_control_rbac_system-3/

The concepts are basically the same and its nice to use and considerably fast for really fine grained access control.

于 2011-05-27T10:50:11.513 回答