假设您有实体 A、B、C 和 D。
- D 与 C 相关
- C 与 B 相关
- B 与 A 相关
此外,用户仅被允许在 D 上运行,如果用户owns A.
在应用程序的某个状态下,您可以包含一个指向访问 D 的页面的链接。因此,您可以将 D 的 ID 作为 GET 或 POST 参数包含在内。
如果用户单击该链接,应用程序将检索 D 的 ID 并开始对 D 进行操作。
简单的应用程序使用像这样的 URL [模 URL 重写]:
http://www.myServer.com/?action=1234&entity=D&ID=23
如何验证用户是否可以对D进行操作?
A)显而易见的解决方案是这样的:给定D,找到C,然后找到B,最终找到A。如果链在某个地方断裂,对 D 的访问将被拒绝。不幸的是,如果实现起来很简单,这需要 4 次数据库访问,而不仅仅是 A 的一次。
B)另一个解决方案是保留D当前会话的ID在一组可访问实体中,供下一个要呈现的页面使用。
C)作为一种替代方案,人们可以加密 GET 和 POST 参数不知何故。对于每个页面请求,第一个操作是解密请求的参数。如果解密操作失败,访问将被拒绝。
D)或者,在无穷大时,散列所有页面中的所有链接,在会话中保留一个将哈希值与 URL 关联起来的映射,并且仅将哈希值写入网页。
E)最后,您可以在 D 中保留对 A、B 和 C 的引用,在 C 中保留对 A 和 B 的引用,在 B 中保留对 A 的引用。因此,在每一级别,人们都能够立即找到根 entity.
遇到这种情况你的解决办法是什么?为什么?
虽然我包含了 PHP 标签,但我不想将这个问题集中到一种语言上。我很高兴收到一般性建议。或者已经在例如中实施的解决方案ORM layers.
UPDATE-1
最后我选择了D).
一般原则:
确保某种从属实体的 ID 始终以安全/可信的方式传递。这样,第三方就无法改变他们的价值观。
Details:
此选项在设计上提供了许多好处:
首先,链接页面的 ID 或其他参数永远不会到达浏览器。代替
http://www.myServer.com/?action=1234&entity=D&ID=23
大多数页面都是这样链接的
http://www.myServer.com/?forwardHash=78sd7sdf98asd7ad5aa76asa4a465
所有参数下一页要执行的内容已完全保存在用户会话中.
由于页面的所有参数都保存在用户会话中,需要更少的检查。特别是,上面提到的关系依赖性检查不再使用。如果用户会话中存在某些内容,则该内容是从之前的内容中放入的可信对话步骤.
此外,人们甚至可以强制用户仅调用当前呈现页面上可用的链接。每次调用链接时,应用程序可能会使页面的所有其他链接无效。因此,用户将无法在多个窗口中打开页面并认为他们看到了应用程序的两种不同“状态”。如果他们调用链接两次,应用程序可能会显示错误消息。
最后,人们可以直接建立我称之为的东西子工作流程对话框:您可以通过将当前页面的 URL 推送到会话中的连续堆栈并打开编辑对话框步骤。用户可以有序结束或有意取消对话工作流程。 A取消工作流程链接如果连续堆栈不为空,则可能会自动显示为用户选项。
通过将延续保留在会话中的堆栈上,它可以与当前运行的对话步骤完全隔离。对话步骤甚至不知道有关其调用者的任何信息。
通过将功能包装在一个小的管理器调用中,子流程最终调用 FlowManager::finishFlow()。此调用从堆栈中弹出一个延续并将浏览器重定向到此页面 -有效地返回到工作流程开始的点.
由于我们使用一堆延续,甚至可以运行从属于其他子工作流程的子工作流程.