[英]How can I do access control via an SQL table?
I'm trying to create an access control system. 我正在尝试创建一个访问控制系统。
Here's a stripped down example of what the table I'm trying to control access to looks like: 这是我试图控制访问的表格的简单示例:
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
And the access control table looks like this: 访问控制表如下所示:
access table:
user_id type object_id access
1 group 1 50
1 thing 1 10
1 thing 2 100
Access can be granted either by specifying the id of the 'thing' directly, or granted for an entire group of things by specifying a group id. 可以通过直接指定“thing”的id来授予访问权限,也可以通过指定组ID来授予整个事物组的访问权限。 In the above example, user 1 has been granted an access level of 50 to group 1, which should apply unless there are any other rules granting more specific access to an individual thing. 在上面的示例中,用户1已被授予对组1的访问级别50,这应该适用,除非有任何其他规则授予对单个事物的更具体的访问权限。
I need a query that returns a list of things (ids only is okay) along with the access level for a specific user. 我需要一个返回一个事物列表的查询(只有id才可以)以及特定用户的访问级别。 So using the example above I'd want something like this for user id 1: 所以使用上面的例子,我想要这样的用户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)
The closest I can come up with is this: 我能想出的最接近的是:
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)
)
But that returns multiple rows, when I only want one for each row in the 'things' table. 但是当我只想在'things'表中的每一行时,它会返回多行。 I'm not sure how to get down to a single row for each 'thing', or how to prioritise 'thing' rules over 'group' rules. 我不确定如何为每个“事物”找到一行,或者如何将“事物”规则优先于“组”规则。
If it helps, the database I'm using is PostgreSQL. 如果它有帮助,我正在使用的数据库是PostgreSQL。
Please feel free to leave a comment if there's any information I've missed out. 如果有任何我错过的信息,请随时发表评论。
Thanks in advance! 提前致谢!
I just read a paper last night on this. 我昨晚就读了一篇论文。 It has some ideas on how to do this. 它有一些关于如何做到这一点的想法。 If you can't use the link on the title try using Google Scholar on Limiting Disclosure in Hippocratic Databases. 如果您无法使用标题上的链接,请尝试使用Google学术搜索在Hippocratic数据库中限制披露。
I don't know the Postgres SQL dialect, but maybe something like: 我不知道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
Incidentally, I don't like the design. 顺便说一句,我不喜欢这个设计。 I would prefer the access table to be split into two: 我更希望访问表分为两部分:
thing_access (user_id, thing_id, access)
group_access (user_id, group_id, access)
My query then becomes: 我的查询变为:
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
I prefer this because foreign keys can now be used in the access tables. 我更喜欢这个,因为外键现在可以在访问表中使用。
While there are several good answers, the most efficient would probably be something like this: 虽然有几个很好的答案,但效率最高的可能是这样的:
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
Which simply uses summarization added to you query to get what you're looking for. 这只是简单地使用添加到您的摘要查询来获取您正在寻找的内容。
Tony: 托尼:
Not a bad solution, I like it, seems to work. 不错的解决方案,我喜欢它,似乎工作。 Here's your query after minor tweaking: 以下是经过小调整后的查询:
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;
And the results look correct: 结果看起来很正确:
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 |
I do completely take the point about it not being an ideal schema. 我完全认为它不是一个理想的架构。 However, I am stuck with it to some extent. 但是,我在某种程度上坚持了它。
Josef: 约瑟夫:
Your solution is very similar to the stuff I was playing with, and my instincts (such as they are) tell me that it should be possible to do it that way. 你的解决方案与我玩的东西非常相似,我的直觉(比如他们)告诉我应该可以这样做。 Unfortunately it doesn't produce completely correct results: 不幸的是,它没有产生完全正确的结果:
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 |
The access level for 'thing 1' has taken the higher 'group' access value, rather than the more specific 'thing' access value of 10, which is what I'm after. “事物1”的访问级别采用了更高的“组”访问值,而不是更具体的“事物”访问值10,这就是我所追求的。 I don't think there's a way to fix that within a GROUP BY
, but if anyone has any suggestions I'm more than happy to be proven incorrect on that point. 我认为在GROUP BY
没有办法解决这个问题,但如果有人有任何建议,我很高兴在这一点上被证明是错误的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.