验证多级关系依赖关系的最佳方法

时间:2011-07-21 22:28:27

标签: php mysql relational-database

假设你有实体A,B,C和D.

  • D与C
  • 有关
  • C涉及B
  • B涉及A

此外,如果用户拥有A ,则只允许用户在D 上操作。

在应用程序中的某个状态下,您包含一个指向页面的链接,该页面访问D.因此,您将D的ID包含为GET或POST参数。

如果用户点击链接,应用程序将检索D的ID并开始对D进行操作。

简单应用使用此类网址[模数网址重写]:

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)或者,无限期地哈希所有网页中的所有链接,在会话中保留一个地图,将哈希与网址相关联,并且只将哈希值写入网页。

E)最后,您可以在D中引用A,B和C,在C中引用A和B,在B中引用A。因此,在每个级别,一个将是能够立即找到根实体。

在这种情况下你的解决方案是什么?为什么?

虽然我包含了PHP标记,但我不想将这个问题集中在一种语言上。我很乐意得到一般性建议。或者已经在例如实施例中实施的解ORM层。

UPDATE-1

最后,我选择了 D)

一般原则:

确保以某种方式从属实体的ID始终以安全/可信的方式传递。以这种方式,第三方无法改变其价值。

详细信息:

此选项通过设计提供了许多好处:

首先,链接页面的ID或其他参数永远不会到达浏览器。而不是

http://www.myServer.com/?action=1234&entity=D&ID=23

大多数网页都像这样链接

http://www.myServer.com/?forwardHash=78sd7sdf98asd7ad5aa76asa4a465

要执行的下一页的所有参数完全保留在用户会话中。

由于页面的所有参数都保存在用户会话中,因此需要检查的次数少得多。特别是,上述关系依赖性检查不再使用。如果用户的会话中有某些内容,则该内容已来自之前受信任的对话框

此外,甚至可以强制用户仅调用当前呈现的页面上可用的链接。每次他们调用链接时,该应用程序可能会使页面的所有其他链接无效。因此,用户将无法在多个窗口中打开页面,并认为他们看到了应用程序的两种不同“状态”。如果他们两次调用链接,应用程序可能会显示错误消息。

最后,可以直接建立我称之为子工作流对话框的内容:您可以通过在会话中的延续堆栈上推送当前页面的URL来启动对话框并打开编辑对话框步骤。用户可以有序地结束或有意取消对话工作流程。如果延续堆栈不为空,则取消工作流程链接可以自动显示为用户选项。

通过在会话中保持堆栈的延续,它与当前运行的对话步骤完全隔离。对话步骤甚至不知道有关其调用者的任何信息。

通过将功能包装在一个小型管理器调用中,子进程最终调用FlowManager :: finishFlow()。此调用会从堆栈中弹出一个延续,并将浏览器重定向到此页面 - 有效地返回到工作流程开始的位置

由于我们使用了一系列延续,因此甚至可以运行从属于其他子工作流程的子工作流程

2 个答案:

答案 0 :(得分:2)

  

明显的解决方案是:给定D,找到C,然后找到B和   最终找到A.如果链条在某个地方中断,那么访问D就可以了   被拒绝。不幸的是,这需要 - 如果实施的话 - 4   数据库访问而不仅仅是A的访问。

我想这可能是可能的。它部分取决于“涉及”的含义,但假设一个相对简单的模式,我希望你能够在一个SQL语句中连接所有四个表。如果缺少部分链,则查询将不返回任何行。

或者我错过了什么?

答案 1 :(得分:1)

我不确定我理解你想要达到的目的但是你不能使用选项 A 来验证是否允许用户在只有一个访问数据库?:

SELECT D.*
  FROM D
    JOIN C 
      ON C.id = D.cid
    JOIN B
      ON B.id = C.bid
    JOIN A.id = B.aid
WHERE A.ownedBy = @userID
  AND D.id = @idToBechecked