【问题标题】:Dynamic role based auth filters in EF contextEF 上下文中基于动态角色的身份验证过滤器
【发布时间】:2017-06-09 12:23:06
【问题描述】:

我一直在努力弄清楚 github 上到底发生了什么事情的细节

所有这一切的关键是我正在尝试将这样的过滤器应用于上下文......

builder.Filter("UserProcesses",
    (Process p, string user) => !p.Roles.Any() || p.Roles.Any(r => r.Users.Any(u => u.UserName == user && (bool)r.Read)),
    (CoreDataContext ctx) => ctx.AuthInfo.Name
);

当评估表达式树并尝试生成 SQL 查询时,这会导致 EF 中的运行时表达式,所以我想我可以尝试其他方法并解决它并想出这个...

builder.Filter("UserProcesses",
    (Process p, string user) => !p.Roles.Any() || p.Roles.Any(r => r.Read ?? false && r.Users.Any(u => u.UserName == user)),
    (CoreDataContext ctx) => ctx.AuthInfo?.Name
);

执行时的最终结果...

var proesses = ctx.Processes.ToList();

...是我得到了 EF 生成的这个 SQL 查询(如在分析器中看到的)...

exec sp_executesql N'SELECT 
    [Extent1].[Id] AS [Id], 
    [Extent1].[FirstProcessStepId] AS [FirstProcessStepId], 
    [Extent1].[Name] AS [Name]
    FROM [Workflow].[Processes] AS [Extent1]
    WHERE ( NOT EXISTS (SELECT 
        1 AS [C1]
        FROM [dbo].[ProcessRoles] AS [Extent2]
        WHERE [Extent1].[Id] = [Extent2].[Process_Id]
    )) OR ( EXISTS (SELECT 
        1 AS [C1]
        FROM  [dbo].[ProcessRoles] AS [Extent3]
        INNER JOIN [dbo].[Roles] AS [Extent4] ON [Extent4].[Id] = [Extent3].[Role_Id]
        WHERE ([Extent1].[Id] = [Extent3].[Process_Id]) AND ((CASE WHEN ([Extent4].[Read] IS NULL) THEN cast(0 as bit) ELSE [Extent4].[Read] END) = 1)
    )) ',N'@DynamicFilterParam_000002 bit',@DynamicFilterParam_000002=NULL

最终结果是我的测试数据应该有 1 个流程实体被过滤掉,因为它链接到用户不属于的角色。

【问题讨论】:

  • 尽量不要发布原始网址

标签: c# sql-server entity-framework linq-to-entities


【解决方案1】:

所以我做了更多的挖掘,结果证明我们可以像这样构建过滤器......

builder.Filter("UserProcesses",
    (Process p, string user) => !p.Roles.Any() || p.Roles.Any(r => r.Read == true && r.Users.Any(u => u.UserName == user)),
    (CoreDataContext ctx) => ctx.AuthInfo?.Name
);

这里的最终结果是角色属性在角色表达式范围内而不是在嵌套表达式内进行评估。

然后我遇到了一个场景,比如说...一个日历有很多事件,我想要一个规则,对每个事件都说这样的话...

当用户处于授予权限的角色中时,他们可以查看所有日历 读取权限。用户可以查看日历中的所有事件 他们有权访问的日历。

这导致生成的复杂 SQL 出现问题,所以我最终写出了这样的规则...

builder.Filter("UserCalendars",
    (Calendar c, string user) => !c.Roles.Any() || c.Roles.Any(r => r.Read == true && r.Users.Any(u => u.UserName == user)),
    (CoreDataContext ctx) => ctx.AuthInfo?.Name
);

builder.Filter("UserEvents",
    (Event e, IQueryable<int> calIds) => calIds.Contains(e.CalendarId),
    (CoreDataContext ctx) => ctx.Calendars.Select(c => c.Id)
);

这允许框架从单个 Db.Events.ToList() 调用中找出它实际上应该运行查询以首先获取所有日历的 id,然后将其作为参数传递给我提出的实际事件问题。

这太酷了!!

【讨论】:

    猜你喜欢
    • 2020-06-08
    • 2016-01-03
    • 1970-01-01
    • 1970-01-01
    • 2014-04-04
    • 2015-05-17
    • 1970-01-01
    • 2023-01-24
    • 2018-08-28
    相关资源
    最近更新 更多