【发布时间】:2011-01-10 21:52:11
【问题描述】:
所以我正在使用 cakephp 制作一个小型网站,并且我的 ACL 设置为每次创建一条内容时,都会创建一条 ACL 规则来将该段内容的所有者链接到实际内容。这允许每个所有者编辑/删除他们自己的内容。这种方法看起来效率很低,因为在数据库中存在与内容等量的 ACL 规则。我很好奇,拥有数百万条内容的大型网站如何解决这个问题?
【问题讨论】:
所以我正在使用 cakephp 制作一个小型网站,并且我的 ACL 设置为每次创建一条内容时,都会创建一条 ACL 规则来将该段内容的所有者链接到实际内容。这允许每个所有者编辑/删除他们自己的内容。这种方法看起来效率很低,因为在数据库中存在与内容等量的 ACL 规则。我很好奇,拥有数百万条内容的大型网站如何解决这个问题?
【问题讨论】:
我在大型网站上工作的访问权限是在应用程序级别确定的。数据库将内容与用户的记录相关联,然后在数据访问/业务逻辑层确定用户是否有足够的权限访问内容。
对于具有动态内容的大型网站,我认为这可能是处理它的最佳方式。
编辑:添加一个更具体的例子。
示例: 好吧,假设我们有一个简单的文件存储站点,用户只能访问他们的数据或其他用户明确与他们共享的数据。
由于这个应用程序相当简单,因为它只是提供文件,它只有三个数据库表,它们是:
Users Table which has columns:
UserId <int> PK
UserName <varchar>
HashedPassword <varchar>
Files Table which has columns:
FileId <int> PK
FileOwnerId <int> FK (this has a foreign key relationship with UserId in the users table)
FileName <varchar>
MimeType <varchar>
FileData <blob>
SharedFile reference table which has columns:
SharedFileIndex <int> PK
FileId <int> FK
UserId <int> FK
现在,我们要在数据访问层中定义一些基本规则,即当用户登录时,他们可以访问他们拥有的文件以及其他用户与他们共享的文件。因此,无论是通过存储过程还是构建查询以发送到数据库服务器,我都会确保我的查询只返回他们有权访问的那些记录。
这里是用户登录时的基本 GetUsersFileList sql 查询:
SELECT FileId, FileName, FileType
FROM Files
WHERE FileOwnerId = @UserId
正如您在此处看到的,我们使用参数化查询来获取用户拥有的文件。此外,我们还将查询共享文件以向用户显示。
现在,如果我们假设每个文件都有自己唯一的 url,例如:
http://mydomain.com/filehandler.php?fileId=123546
然后当我们尝试获取文件时,我们使用与上面类似的查询来尝试获取文件数据:
SELECT FileName, FileType, FileData
FROM Files
LEFT OUTER JOIN SharedFiles on Files.FileId = SharedFiles.FileId
WHERE Files.FileId = @FileId AND (FileOwnerId = @UserId OR SharedFiles.UserId = @UserId)
因此,您会看到,当我们尝试获取文件时,我们仍在查询中使用 UserId,因此,如果用户没有与他们共享文件或者他们不是文件的所有者,则查询的结果将为 0 行。
因此权限取决于用户在数据库中映射到的对象,但实际执行是通过在提供内容之前仔细编写数据访问代码和/或在业务逻辑层中进行额外检查来完成的。
EDIT2:我最熟悉 MSSQL,所以我上面的查询是在 T-SQL 中的,所以对于 MySql 来说语法可能有点偏离。
EDIT3:将业务逻辑层替换为数据访问层,如本例所示,唯一进行的检查是在数据访问查询本身内。
EDIT4:好的,请参考业务逻辑层,因为更复杂的应用程序需要更复杂的权限方案,这可能需要在业务逻辑层中进行额外检查。
【讨论】:
您可以为每组不同的权限设置一个单独的 ACL,而不是为每个内容元素设置一个单独的 ACL。给定用户的大多数内容项将具有相同的权限,因此它们都可以指向相同的 ACL。这也可以让您缓存权限检查(例如“用户 123 有权读取 ACL 456”)。最后,您将拥有非常少的 ACL——只有所有标准的 ACL 和少数例外。
【讨论】:
同样的规则适用于大型和小型网站 - 如果您想要更具体的控制,您必须在数据库中存储更多数据。您尝试解决的问题 [允许用户仅管理他们的内容] 可以使用表之间的简单用户 ID 链接 [例如 users.id articles.userId] 来解决,无需将每一行与用户链接。我建议使用更通用的规则并仅将例外情况(例如允许指定用户编辑其他用户的内容)存储为外部数据。
【讨论】: