我想使用 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)
除非我错过了一些很好的 SQL Server 功能,其中行/记录包含一个名为
.Security
的伪列来实现行级安全性,否则您应该能够简单地编写
dslContext.select()
.from(EMPLOYEE)
.where(EMPLOYEE.SECURITY.in(1, 2))
.fetch();
有关 jOOQ 谓词构建的更多信息,请参阅此处的手册:
特别是
IN
谓词:
jOOQ 3.19 引入了对#2682的政策支持,另请参阅:
通过策略,您可以简单地在您的
Configuration
上指定类似的内容:
Configuration configuration = ...;
configuration.set(new DefaultPolicyProvider()
.append(
EMPLOYEE,
EMPLOYEE.SECURITY.in(1, 2))
);
现在,所有查询(包括 DML)都将阻止访问谓词不成立的数据
TRUE
。
根据您的评论,您正在寻找一种通用方法来使用附加谓词修补所有 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));
}
}
}
当然,上述内容还有改进的空间。欢迎在用户组
讨论用例VisitListener
并实际转换 jOOQ 的查询的 AST 表示形式。这记录在这里:
虽然上述方法有效,但我个人建议您为此使用视图并向开发人员隐藏实际的表。示例:
CREATE VIEW v_employee AS
SELECT a, b, c, ...
FROM t_employee
WHERE t_employee.security in (1, 2)
通过适当的拨款,您可以向开发人员隐藏表,确保他们只会使用始终具有所需谓词的视图