DbContext模型构建器中的用户详细信息

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DbContext模型构建器中的用户详细信息相关的知识,希望对你有一定的参考价值。

我是razor pages / efcore / aspnet身份的新手,并且一直试图解决这个问题,但它击败了我。

基本上,我使用AspNet Identity进行用户身份验证和授权。我已经使用额外的OrganisationId扩展了AspNetUsers,这是一个组织实体的FK;并在身份声明商店中添加了ID作为声明。这很好用。

现在,我需要根据经过身份验证的用户的organisationId设置efcore global filter,以便他们只能查看分配给其组织的数据。

但是,我无法访问模型构建器中经过身份验证的用户详细信息。

public class SDMOxContext : IdentityDbContext<
        ApplicationUser, ApplicationRole, string,
        ApplicationUserClaim, ApplicationUserRole, ApplicationUserLogin,
        ApplicationRoleClaim, ApplicationUserToken>
    {

        public SDMOxContext(DbContextOptions<SDMOxContext> options)
            : base(options)
        { }

        protected override void OnModelCreating(ModelBuilder builder)
        {

            base.OnModelCreating(builder);
        // Set global filter so users can only see projects within their organisation.
        builder.Entity<Project>().HasQueryFilter(project => project.OrganisationId == 1);

    }

我需要输入用户organisationid而不是全局过滤器中的1,而用户声明存储为用户声明。通常我得到它:

User.FindFirstValue("OrganisationId")

但是,用户在当前上下文中不存在。

答案

所以我需要在稍后阶段应用查询过滤器,即。用户认证后?从中间层/逻辑层方法开始的任何指针?

虽然这是对架构的看法,但我将其分解为:

数据层 - 此层负责在执行的应用程序之外(通常)访问资源。这包括;数据库,文件IO,Web Api等

业务/逻辑层 - 此层的职责(可以进一步细分)应该验证,授权,验证和构建代表业务需求的对象。要构建这些对象,它可能会使用一个或多个数据访问对象(例如,它可能使用IO DA从本地文件系统或Azure存储中检索映像,并使用数据库DA检索有关该映像的元数据)。

Presentation / Exposure-Tier - 该层的职责是将对象包装并转换为消费者需求(winforms,wpf,html,json,xml,二进制序列化等)。

通过将逻辑排除在数据层之外(即使在多租户系统中),您可以获得跨所有系统访问数据的能力(并相信我在这里需要投入大量资金)。

这可能比我在这么短的地方和我的意见中解释得多。我将要离开很多但是这里去了。

数据层

namespace ProjectsData
{
  public interface IProjectDA 
  { 
    IProjectDO GetProject(Guid projectId, Guid organizationId);
  }
  private class ProjectDA : DbContext, IProjectDA
  {
    public ProjectDA (...)
    public IEnumerable<ProjectDO> Projects { get; set; }
    protected override void OnModelCreating(ModelBuilder builder) {... }
    public IProjectDO GetProject(Guid projectId, Guid organizationId)
    {
      var result = Projects
        .FirstOrDefault(p => p.Id == projectId && OrganizationId = organizationId);
      return result;
    }
  }

  public interface IProjectDO{ ... }
  private class ProjectDO: IProjectDO
  {
    public Guid Id { get; set; }
    public Guid OrganizationId { get; set; }
    public Guid CategoryId { get; set; }
  }
}

逻辑

namespace ProjectBusiness
{
  public interface IProjectBO { .. }
  public interface IOrganization 
  { 
    Guid OrganizationId { get; }
  }
  private class ProjectBA : IProjectBO
  {
    private readonly IProjectDA _projectDA;
    private readonly IIdentity _identity;
    private readonly IOrganization _organization;
    public  ProjectLogic(IProjectDA projectDA, 
      IIdentity identity,
      IOrganizationContext organizationContext)
    {
      _projectDA = projectDA;
      _identity = identity;
    }
    public IProjectBO GetProject(Guid id)
    {
      var do = _projectDA
        .GetProject(id, _organization);

      var result = map.To<ProjectBO>(do);

      return result;
    }
  }
  public interface IProjectBO { .. }
  private class ProjectBO 
  { 
    public Guid Id { get; set; }
    public Guid OrganizationId { get; set; }
    public Guid CategoryId { get; set; }
  }
}

因此,在这些情况下,数据层知道请求的类型,但不是多租户意识。它不是基于任何东西限制所有请求。该架构在许多方面都是有利的。

首先,在上面的示例中,您的产品起飞,您的主管想知道哪些类别最受欢迎。

namespace StatisticsBusiness
{
  public interface IStatisticsBO 
  {
    IEnumerable<ICategoryStatisticBO> CategoryStatistics { get; set; }
  }
  public interface ICategoryStaticBO
  {
    Guid CategoryId { get; }
    int ProjectCount { get; }
  }
  private class StatisticsBA : IStatisticsBO
  {
    private readonly IProjectDA _projectDA;
    private readonly IIdentity _identity;
    public  ProjectLogic(IProjectDA projectDA, 
      IIdentity identity)
    {
      _projectDA = projectDA;
      _identity = identity;
    }

    public IEnumerable<IProjectBO GetOrderedCategoryPopularity()
    {
      var dos = _projectDA
        .GetProjectCategoryCounts()

      var result = map.To<IEnumerable<IStatisticsBO>>(dos);

      return result;
    }
  }
  public interface IStatisticsBO{ .. }
  private class StatisticsBO 
  { 
    public Guid CategoryId { get; }
    public int ProjectCount { get; }
  }
}

注意:有些人喜欢将表达式作为谓词传递。两者都有其优点和缺点。如果您决定使用谓词路由,则必须确定所有数据访问类型是否都使用谓词。只是意识到使用针对IO或Web Api的谓词可能会更加努力,值得。

其次,某些要求会导致您无法使用实体框架。您可以用Dapper或其他一些新的更好的技术/框架替换它。所有你必须创建新的I<whataver>DA类,因为消费逻辑不知道除了那些接口之外的任何东西(programming against an interfaceL in SOLID programming principlesI in SOLID programming principles)。

我并不是一直使用这种模式,因为对于一些较小的网站来说,它的收益太多了。

另一答案

我建议将解决方案分为两部分

  1. 在dbcontext中添加组织ID,非常类似于多租户环境中的租户ID。例如,请参阅此link
  2. 下一个挑战是将组织ID作为参数传递给DbContext构造函数。为此,您可以为DbContext创建工厂。由于您将OrganizationId存储在声明中。工厂可以访问相同的声明HttpContext并将组织ID作为参数传递,同时立即执行dbContext。

这不是完美的,但可以给你一个起点。

以上是关于DbContext模型构建器中的用户详细信息的主要内容,如果未能解决你的问题,请参考以下文章

javascript 在移动构建器中删除页面bg图像(页面bg不是为了在不重新生成移动设备的情况下更新而构建的)。详细信息:https://instapage.atlassian。

javascript 在移动构建器中删除页面bg图像(页面bg不是为了在不重新生成移动设备的情况下更新而构建的)。详细信息:https://instapage.atlassian。

将 DbContext 与依赖注入一起使用

如何使用 Net Core 在 DbContext 中获取用户信息

通过加入用户详细信息实体从 IdentityDbContext 获取用户详细信息

ANT 构建:解析器中的变量:工件未定义