我正在尝试创建一个访问控制系统。

以下是我试图控制访问权限的表格的简要示例:

things table:
id   group_id   name
1    1          thing 1
2    1          thing 2
3    1          thing 3
4    1          thing 4
5    2          thing 5

访问控制表如下所示:

access table:
user_id  type   object_id  access
1        group  1          50
1        thing  1          10
1        thing  2          100

可以通过直接指定“thing”的id来授予访问权限,也可以通过指定组ID来授予整个事物组的访问权限。在上面的示例中,用户1被授予了对组1的访问级别50,这应该适用,除非有任何其他规则授予对单个事物的更具体的访问权。

我需要一个返回一个事物列表的查询(只有id才可以)以及特定用户的访问级别。所以使用上面的例子,我想要这样的用户ID 1:

desired result:
thing_id   access
1          10
2          100
3          50   (things 3 and 4 have no specific access rule,
4          50   so this '50' is from the group rule)
5               (thing 5 has no rules at all, so although I 
                still want it in the output, there's no access
        level for it)

我能想出的最接近的是:

SELECT * 
FROM things 
LEFT JOIN access ON 
    user_id = 1
    AND (
        (access.type = 'group' AND access.object_id = things.group_id)
        OR (access.type = 'thing' AND access.object_id = things.id)
    )

但是当我只想在'things'表中的每一行时,它会返回多行。我不确定如何针对每个“事物”找到一行,或者如何将“事物”规则优先于“组”规则。

如果有帮助,我使用的数据库是PostgreSQL。

如果有任何我错过的信息,请随时发表评论。

提前致谢!

有帮助吗?

解决方案

我不知道Postgres SQL方言,但可能是这样的:

select thing.*, coalesce ( ( select access
                             from   access
                             where  userid = 1
                             and    type = 'thing'
                             and    object_id = thing.id
                           ),
                           ( select access
                             from   access
                             where  userid = 1
                             and    type = 'group'
                             and    object_id = thing.group_id
                           )
                         )
from things

顺便说一下,我不喜欢这个设计。我更希望将访问表分成两部分:

thing_access (user_id, thing_id, access)
group_access (user_id, group_id, access)

我的查询变为:

select thing.*, coalesce ( ( select access
                             from   thing_access
                             where  userid = 1
                             and    thing_id = thing.id
                           ),
                           ( select access
                             from   group_access
                             where  userid = 1
                             and    group_id = thing.group_id
                           )
                         )
from things

我更喜欢这个,因为现在可以在访问表中使用外键。

其他提示

我昨晚刚读了一篇论文。它有一些关于如何做到这一点的想法。如果您无法使用标题上的链接,请尝试在在希波克拉底限制披露中使用Google学术搜索数据库。

虽然有几个好的答案,但最有效的可能是这样的:

SELECT things.id, things.group_id, things.name, max(access) 
FROM things 
LEFT JOIN access ON 
        user_id = 1 
        AND (
                (access.type = 'group' AND access.object_id = things.group_id)
                OR (access.type = 'thing' AND access.object_id = things.id)
        )
group by things.id, things.group_id, things.name

其中只使用添加到您查询中的摘要来获取您要查找的内容。

托尼:

不是坏的解决方案,我喜欢它,似乎有效。这是经过细微调整后的查询:

SELECT 
    things.*, 
    coalesce ( 
        (   SELECT access 
            FROM access 
            WHERE user_id = 1 
                AND type = 'thing' 
                AND object_id = things.id
        ), 
        (   SELECT access 
            FROM access 
            WHERE user_id = 1 
                AND type = 'group' 
                AND object_id = things.group_id 
        ) 
    ) AS access
    FROM things;

结果看起来是正确的:

 id | group_id |  name   | access 
----+----------+---------+--------
  1 |        1 | thing 1 |     10
  2 |        1 | thing 2 |    100
  3 |        1 | thing 3 |     50
  4 |        1 | thing 4 |     50
  5 |        2 | thing 5 |       

完全认为它不是理想的架构。但是,我在某种程度上坚持了它。


约瑟夫:

你的解决方案与我玩的东西非常相似,我的直觉(比如他们)告诉我应该可以这样做。不幸的是,它没有产生完全正确的结果:

 id | group_id |  name   | max 
----+----------+---------+-----
  1 |        1 | thing 1 |  50
  2 |        1 | thing 2 | 100
  3 |        1 | thing 3 |  50
  4 |        1 | thing 4 |  50
  5 |        2 | thing 5 |    

“事物1”的访问级别采用了更高的“组”访问值,而不是更具体的“事物”访问值10,这就是我所追求的。我不认为有一种方法可以在 GROUP BY 中修复它,但如果有人有任何建议,我很高兴在这一点上被证明是错误的。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top