首先,让我作为序言说我是发展中国家的新手。我大约一个月前开始作为实习生,所以很有可能无法正确解释自己。为此,我深表歉意。
现在,这是问题所在:我正在使用C#和Entity Framework Core为API编写一组端点。根据设计,过滤应该在数据库级别进行,因此我们为此使用RLS。为此,我编写了以下谓词和策略:
@imports
和
USE [DBO]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [sec].[RestrictApplicationsByUser](@ApplicationId int)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN SELECT 1 AS RestrictApplicationsByUserResult
WHERE
@ApplicationId IN (SELECT
ApplicationId
FROM
[usr].[UserApplications]
WHERE
UserId = CAST(SESSION_CONTEXT(N'UserId') AS uniqueidentifier))
OR SESSION_CONTEXT(N'UserId') IS NULL;
GO
表设置如下:
USE [DBO]
GO
CREATE SECURITY POLICY [sec].[FilterApplicationByUser]
ADD FILTER PREDICATE [sec].[RestrictApplicationsByUser]([ApplicationId]) ON [app].[Applications]
WITH (STATE = ON, SCHEMABINDING = ON)
GO
具有[app].[Applications]
和ApplicationId
作为列,而Name
具有[usr].[UserApplications]
和UserId
作为列。
这里的想法是,每当用户查询ApplicationId
表时,他只会看到他管理的那些应用程序(此关系在[app].[Applications]
表上设置)。据我所知,这可行。
现在的问题是,在[usr].[UserApplications]
表上插入新记录及其关联在[app].[Applications]
表中会产生500个服务器错误。
使用SQL事件探查器,我注意到每当我尝试发出POST请求时,这两个查询就会以以下顺序运行:
[usr].[UserApplications]
和
exec sp_executesql N'SET NOCOUNT ON;
INSERT INTO [app].[Applications] ([Name])
VALUES (@p0);
SELECT [ApplicationId]
FROM [app].[Applications]
WHERE @@ROWCOUNT = 1 AND [ApplicationId] = scope_identity();
',N'@p0 nvarchar(2000)',@p0=N'test''
go
我经验不足,因此第一个查询是原子操作,因此在尝试选择exec sp_executesql N'SET NOCOUNT ON;
INSERT INTO [usr].[UserApplications] ([UserId], [ApplicationId])
VALUES (@p1, @p2);
',N'@p1 uniqueidentifier,@p2 int',@p1='<user_guid>',@p2=<PK_value>
go
失败时尝试执行此操作,因为它与请求用户之间尚不存在关联,因为它尚未创建(那将是第二个查询)。阅读一番之后,看来似乎是由Entity Framework执行特定的SELECT,以便获取表上的下一个可用ID。
如果您仍然与我在一起,而我发现的答案是正确的,那么我认为我遇到了鸡问题或鸡蛋问题。
这可以解决吗?如果是这样,我应该在哪里寻找问题的根源? RLS政策?我的API代码?
非常感谢您给我的任何提示或建议。