Ama*_*mam 3 sql-server row-level-security sql-server-2016
在单个 SQL Server 2016 数据库上运行多租户应用程序。我有一个 RLS(行级安全性)谓词customer_id
(每个租户唯一)并且该列存在于所有表中。
CREATE FUNCTION dbo.[RLSPredicate] (@CustomerId bigint)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN SELECT 1 AS RLSPredicateResult WHERE (@CustomerId =
CAST(SESSION_CONTEXT(N'customer_id') AS bigint))
GO
-- two table example
CREATE SECURITY POLICY [dbo].[RLSPolicy]
ADD FILTER PREDICATE [dbo].[RLSPredicate] ([customer_id]) ON [dbo].[user],
ADD FILTER PREDICATE [dbo].[RLSPredicate] ([customer_id]) ON [dbo].
[user_email]
WITH (STATE = ON, SCHEMABINDING = ON)
GO
-- Sample Query
EXEC sp_set_session_context @key=N'customer_id', @value='1231312'
select top 1000 * from [user] where customer_id = 1231312
Run Code Online (Sandbox Code Playgroud)
使用上面的设计,EXEC sp_set_session_context
总是需要在任何用户查询命中数据库之前执行,但是我们有应用团队忘记添加代码的情况EXEC sp_set_session_context
在新项目中情况。
问题是无法保证进入数据库的查询总是包含EXEC sp_set_session_context
在其中。查询以各种形式出现,EXEC
, sp_executesql
, adhoc 等。
我想知道是否有任何方法可以重新设计过滤谓词,以便从数据库中强制执行 RLS,并EXEC sp_set_session_context
在每次查询之前删除运行的依赖性。
有超过 50 万个customer_id
值。
我认为您应该使用登录触发器并SET CONTEXT_INFO
引用 BoL
将最多 128 字节的二进制信息与当前会话或连接相关联。
然后您可以通过使用 select 调用该函数来检索数据
IE SELECT CONTEXT_INFO()
然后,您可以使用从与 Row Level Security 的连接中调用的数据来实现您想要的过滤。
如果您运行的是 SQL Server 2016 或更高版本,则应改用更现代的session_context()
函数 - 请参阅Aaron Bertrand 的Phase out CONTEXT_INFO() in SQL Server 2016 with SESSION_CONTEXT()。