【问题标题】:How to filter SQL rows, depending on a user's roles?如何根据用户的角色过滤 SQL 行?
【发布时间】:2016-06-06 05:51:04
【问题描述】:

在我的应用程序中,每个用户都可以拥有多个授权角色。根据他的角色,应该允许用户查看某些数据摘录。我想通过 REST-API 从我的关系数据库中提供这些数据。

例如:

table "Role"
UserName | Role
---------------------------
Anne     | ViewFreshFruits
Mike     | ViewFreshFruits
Mike     | ViewTinySoft

table "Company"
Name        | Address     | Role
--------------------------------------------
FreshFruits | 123 America | ViewFreshFruits 
TinySoft    | 543 Britain | ViewTinySoft

table "Contract"
ID  | CompanyName | Dollar
---------------------------
147 | FreshFruits | 15549
148 | FreshFruits | 16321
149 | TinySoft    | 2311

要实现 REST-Resource http://api:8080/Application/Contracts/getAll,数据(未经权限检查)可以简单地是:

SELECT Contract.* FROM Contract

但安妮只能看到 147 和 148。迈克可以看到 147、148、149。而且托米不能得到任何结果。

我开始像这样实现权限检查:

SELECT Contract.* FROM Contract
INNER JOIN Company ON Contract.CompanyName = Company.Name
INNER JOIN Role ON Role.Role = Company.Role
WHERE User = @CurrentlyAuthenticatedUser

随着我的数据库中表的数量增加,这种 SQL 变得越来越复杂。我正在寻找一种更简单的方法:不太复杂且更易于维护。性能不是我最关心的问题。

如何尽可能简单地根据用户过滤某些数据行?

我使用的是 Microsoft SQL Server 2012、Java Tomcat 8 和连接池。

【问题讨论】:

    标签: java sql rest authorization


    【解决方案1】:

    这似乎是最简单的创建和维护方法。

    如果您想要一个更快的 SQL 查询,不需要连接,您可以基于该查询创建一个物化视图,但没有WHERE 子句和列选择上的User

    SELECT User, Contract.* FROM Contract
    INNER JOIN Company ON Contract.CompanyName = Company.Name
    INNER JOIN Role ON Role.Role = Company.Role
    

    这样,您将拥有一个虚拟表,该表可以保存该查询并保持最新状态,以便快速检索身份验证数据。对于select,您只需:

    SELECT * FROM MaterializedView
    WHERE User = @CurrentlyAuthenticatedUser
    

    【讨论】:

    • 感谢您的回答。我仍然不相信,因为视图定义几乎和我最初的方法一样复杂,我最终会遇到大量数据库查询,并且根据用户和合同的数量,这可能会占用大量磁盘空间。
    • 磁盘空间不受存储过程或函数的影响
    • 据我所知,materialized 视图确实会占用磁盘空间。不是吗?
    • @slartidan 是的,他们有。这就是对它的查询速度更快的原因,因为它们访问该物化视图上的数据并且不需要计算查询。这是旧的选择,在节省空间(视图)或处理(物化视图)之间。
    【解决方案2】:

    您传递角色的存储过程怎么样。或者为了简化您选择使用视图来隐藏一些细节。

    编辑

    在公司和授权表(或存储过程或 CTE)上创建视图

    CREATE VIEW CompanySecurity AS SELECT Company.*, role.username FROM Company INNER JOIN Role ON Role.Role = Company.Role

    如果您想要合同详细信息,请将该视图加入到 CompanySecurity 并过滤用户名

    如果您想查看销售,请将销售加入 CompanySecurity 并过滤用户名

    【讨论】:

    • 如果您需要更简单的查询,这是最佳答案。但不要使用存储过程,而是使用用户定义的函数。它仅限于选择,但与存储过程不同,它可以用作表。因为查询只是一个选择,所以最好的选择是 UDF。
    • 似乎创建这些存储过程或函数会将复杂性移动到数据库中;但不会降低复杂性。
    • 不幸的是,您需要一些复杂性才能添加功能!
    • 你不需要在每个表上都实现。您是否需要通过您对具有安全性的公司的看法链接的销售摘要
    • 很抱歉,我不明白您的最后评论。什么是“有保障的公司”?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-04
    • 1970-01-01
    • 2019-03-17
    • 2014-01-17
    • 2019-08-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多