将筛选器参数传递给DBContext

人气:714 发布:2022-10-16 标签: c# dbcontext asp.net-core entity-framework-core razor-pages

问题描述

在ASP.NET Core Web应用程序中,将值传递给DB上下文类以将其用作筛选器的正确方式是什么?

我需要筛选在ASP.NET Core Web应用程序的所有页面上返回的数据。筛选器将基于登录的用户。如果登录用户来自分支机构6108,则他们应该只看到该分支机构的数据。如果我使用原始值,我可以通过说

进行筛选
modelBuilder.Entity<Branch>().HasQueryFilter(b => b.BranchID == 6108);

问题是我们有50多个分支机构,因此任何登录用户的数字都不同。

所以理想情况下,我希望它写成

modelBuilder.Entity<Branch>().HasQueryFilter(b => b.BranchID == branchFilter);

其中分支筛选器是我通过使用

获取登录用户后发现并传递的值
@User.Identity.Name

推荐答案

当您启动数据库上下文时,您可以注入所需的用户数据,将其存储在字段中,然后在查询中使用它。为此,您可以为该用户数据创建一个接口,然后通过依赖项注入注入用户数据的实现。之后,您可以在HasQueryFilter中使用该字段。

例如:

public class YourDbContext : DbContext
{
    private string branchId;
    private string userId;


    public YourDbContext(DbContextOptions<YourDbContext> options, IGetUserProvider userData) : base(options)
    {          
        tenantId = userData.BranchId;
        userId = userData.UserId;
    }
// ...
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Branch>().HasQueryFilter(b => b.BranchID == branchId);
    }
}

以及如何从HttpContext获取用户的示例,其中您的用户持有对分支的声明。当然,您应该拥有与您的用例相关的IGetUserProvider实现。

public interface IGetUserProvider
{
    string UserId { get; }
    string BranchId { get; }
}

public class GetUserProvider : IGetUserProvider
{
    public string UserId { get; }
    public string BranchId { get; }

    public GetTenantClaimsProvider(IHttpContextAccessor accessor)
    {
        UserId = accessor.HttpContext?.User.Claims.SingleOrDefault(x => x.Type == UserIdentifierClaimName)?.Value;
        BranchId = accessor.HttpContext?.User.Claims.SingleOrDefault(x => x.Type == BranchIdentifierClaimName)?.Value;
    }
}
或者,您可以在DbContext的实现上创建公共属性或方法,但您需要记住在查询任何数据集之前始终设置数据。这是一个极有可能出现的错误,其后果相当严重,可以通过注入所需数据来避免。

有关此主题的完整指南,请阅读Jon P.Smith提出的设计:https://www.thereformedprogrammer.net/part-4-building-a-robust-and-secure-data-authorization-with-ef-core/

349