JOOQ 中的行级安全性实现

Posted

技术标签:

【中文标题】JOOQ 中的行级安全性实现【英文标题】:Row Level Security implementation in JOOQ 【发布时间】:2013-06-23 20:31:20 【问题描述】:

我想使用 JOOQ 库在 Java 中实现 oracle 行级安全类型的功能

这是一个示例 JOOQ 查询代码:

Result<Record> result = dslContext.select().from(Employee.EMPLOYEE).fetch();

上面的代码会生成如下SQL:

select [dbo].[Employee].Id,... from [dbo].[Employee]

我想添加一个 where 子句来过滤特定于用户安全的数据,如下所示:

select [dbo].[Employee].Id,... from [dbo].[Employee] WHERE [dbo].[Employee].Security IN (1,2)

【问题讨论】:

【参考方案1】:

显式谓词

除非我缺少一些不错的 SQL Server 功能,其中行/记录包含一个名为 .Security 的伪列来实现行级安全性,否则您应该能够简单地编写

dslContext.select()
          .from(EMPLOYEE)
          .where(EMPLOYEE.SECURITY.in(1, 2))
          .fetch();

有关 jOOQ 谓词构建的更多信息,请参阅此处的手册:

http://www.jooq.org/doc/latest/manual/sql-building/conditional-expressions

尤其是IN 谓词:

http://www.jooq.org/doc/latest/manual/sql-building/conditional-expressions/in-predicate

使用 jOOQ 的 ExecuteListener 的一般解决方案

鉴于您的 cmets,您正在寻找一种通用方法来使用附加谓词修补所有 SQL 语句,无论特定程序员正在输入什么。

您可以使用 jOOQ 做到这一点,但请注意,如果程序员绕过 jOOQ,这只会帮助您执行谓词,而不是保证它。您可以做的是设置一个ExecuteListener,拦截renderStart() 事件以修补/替换正在执行的查询。大致如下:

@Override
public void renderStart(ExecuteContext ctx) 
    if (ctx.query() instanceof Select) 

        // Operate on jOOQ's internal query model
        SelectQuery<?> select = null;

        // Check if the query was constructed using the "model" API
        if (ctx.query() instanceof SelectQuery) 
            select = (SelectQuery<?>) ctx.query();
        

        // Check if the query was constructed using the DSL API
        else if (ctx.query() instanceof SelectFinalStep) 
            select = ((SelectFinalStep<?>) ctx.query()).getQuery();
        

        if (select != null) 
            // Use a more appropriate predicate expression
            // to form more generic predicates which work on all tables
            select.addConditions(EMPLOYEE.SECURITY.in(1, 2));
        
    

当然,上述内容还有改进的余地。随时在user group

上讨论用例

使用 jOOQ 的 VisitListener 的通用解决方案

如果您愿意深入了解 jOOQ 的内部结构,还可以尝试实现 VisitListener 并实际转换 jOOQ 的 AST 表示形式的查询。这记录在这里:

http://www.jooq.org/doc/latest/manual/sql-building/queryparts/custom-sql-transformation/

使用视图的一般解决方案

虽然上述方法有效,但我个人建议您为此使用视图,并向开发人员隐藏实际的表格。示例:

CREATE VIEW v_employee AS
SELECT a, b, c, ... 
FROM t_employee
WHERE t_employee.security in (1, 2)

通过适当的授权,您可以向开发人员隐藏表格,确保他们只会使用始终存在所需谓词的视图

【讨论】:

您的代码可以工作,这意味着所有开发人员必须记住在每次查询数据时添加安全条件,如果他们错过添加此条件,这将是一个安全漏洞,因此我想到注入安全条件在一个常见的地方,比如执行监听器,这样开发人员就不必一次又一次地这样做。 谢谢。我只想为几个表(不是全部)添加条件。有没有办法在注入安全条件之前检查renderStart中的表名? @Venkat:还没有。更复杂的 ExecuteListener 机制已在路线图中,但尚未成为优先事项:github.com/jOOQ/jOOQ/issues/1691

以上是关于JOOQ 中的行级安全性实现的主要内容,如果未能解决你的问题,请参考以下文章

如何实现对亚马逊 Redshift 的原始 sql 访问的行级安全性 (RLS)?

实体框架的行级安全性

使用 MS SQL 的 JAX-RS 中的行级安全性

组的行级安全性或使组可以访问行

Postgres 规范化表上的行级安全性

SQL Server 2019 中 Polybase 外部表的行级安全性可能吗?