简体   繁体   English

如何通过SQL表进行访问控制?

[英]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.

相关问题 如何通过SQL提取Sybase(12.5)表DDL? - How do I extract Sybase (12.5) table DDL via SQL? 如何通过SQL自动将月度记录插入表中? - How do I Automatically insert monthly records into a table via SQL? 如何查看为创建现有表而生成的 sql 访问? - How can I view the sql access generated to create an existing table? 如何在Access SQL的列别名中使用表名? - How can I use the table name in a column alias in Access SQL? 如何从 SQL 中的同一个表中进行递归选择? - How can i do a recursive select from the same Table in SQL? 如何在NHibernate中使用sql查询创建表? - How Can I Do Create Table by using sql query in NHibernate? 如何通过SQL将访问权限中的“索引:是(无重复)”约束更改为“索引:否”? - How do I change the “Indexed: Yes (No Duplicates)” constraint in Access to “Indexed: No” via SQL? 如何通过EntLib 5.0将表值参数传递给SQL Server 2008? - How do I pass a table-valued parameter to SQL Server 2008 via EntLib 5.0? 如何使用来访问SQL Server数据库。 通过设置位置命名 - How can I access a SQL Server database with . in name via set-location 我如何通过 GridConfiguration 提取表的列列表,类似于在常规 SQL 中的做法? - How can I pull a table's column list via GridConfiguration similar to how it's done in regular SQL?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM