C# DbContext模型生成器中的用户详细信息

C# DbContext模型生成器中的用户详细信息,c#,entity-framework,razor,asp.net-identity,C#,Entity Framework,Razor,Asp.net Identity,我对razor pages/efcore/aspnet identity还不熟悉,一直想弄明白这一点,但它打败了我 基本上,我使用AspNet标识进行用户身份验证和授权。我用一个额外的OrganizationID扩展了AspNetUsers,这是一个FK到Organization实体;并将该ID作为声明添加到标识声明存储中。这个很好用 现在,我需要根据经过身份验证的用户的OrganizationID设置一个值,以便他们只能查看分配给其组织的数据 但是,我无法访问ModelBuilder中经过身份

我对razor pages/efcore/aspnet identity还不熟悉,一直想弄明白这一点,但它打败了我

基本上,我使用AspNet标识进行用户身份验证和授权。我用一个额外的OrganizationID扩展了AspNetUsers,这是一个FK到Organization实体;并将该ID作为声明添加到标识声明存储中。这个很好用

现在,我需要根据经过身份验证的用户的OrganizationID设置一个值,以便他们只能查看分配给其组织的数据

但是,我无法访问ModelBuilder中经过身份验证的用户详细信息

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);

    }

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

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

  • 在dbcontext中添加组织id,就像多租户环境中的租户id一样。看看这个例子

  • 下一个挑战是将组织id作为参数传递给DbContext构造函数。为此,可以为DbContext创建工厂。因为您将OrganizationId存储在索赔中。工厂可以访问相同的声明HttpContext,并在实例化dbContext时将组织id作为参数传递

  • 这并不完美,但可以给你一个起点


    因此,我需要在稍后阶段应用查询过滤器,即在用户身份验证之后?从哪里开始使用中间层/逻辑层方法

    虽然这是一个关于建筑的观点,但我将其分解如下:

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

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

    表示/公开层-该层的职责是将对象包装并转换为用户需要的内容(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; }
      }
    }
    
    名称空间项目数据
    {
    公共接口IProjectDA
    { 
    IProjectDO GetProject(Guid projectId、Guid organizationId);
    }
    私有类ProjectDA:DbContext,IProjectDA
    {
    公共项目a(…)
    公共IEnumerable项目{get;set;}
    模型创建时受保护的覆盖无效(ModelBuilder){…}
    公共IProjectDO GetProject(Guid projectId、Guid organizationId)
    {
    var结果=项目
    .FirstOrDefault(p=>p.Id==projectId&&OrganizationId=OrganizationId);
    返回结果;
    }
    }
    公共接口IProjectDO{…}
    私有类ProjectDO:IProjectDO
    {
    公共Guid Id{get;set;}
    公共Guid组织ID{get;set;}
    公共Guid类别ID{get;set;}
    }
    }
    
    逻辑

    名称空间项目业务
    {
    公共接口IProjectBO{..}
    公共界面组织
    { 
    Guid组织ID{get;}
    }
    私有类项目BA:IProjectBO
    {
    私有只读IProjectDA_projectDA;
    私有只读身份标识;
    私人只读组织;
    公共项目逻辑(IProjectDA projectDA,
    身份识别,
    IOR组织上下文(组织上下文)
    {
    _projectDA=projectDA;
    _身份=身份;
    }
    公共IProjectBO GetProject(Guid id)
    {
    var do=\u projectDA
    .GetProject(id,组织机构);
    var结果=映射到(do);
    返回结果;
    }
    }
    公共接口IProjectBO{..}
    私有类ProjectBO
    { 
    公共Guid Id{get;set;}
    公共Guid组织ID{get;set;}
    公共Guid类别ID{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; }
      }
    }
    
    名称空间统计业务
    {
    公共接口IStatisticsBO
    {
    IEnumerable CategoryStatistics{get;set;}
    }
    公共接口ICategoryStaticBO
    {
    Guid类别ID{get;}
    int ProjectCount{get;}
    }
    私人统计BA:IStatisticsBO
    {
    私有只读IProjectDA_projectDA;
    私有只读身份标识;
    公共项目逻辑(IProjectDA projectDA,
    身份(身份)
    {
    _projectDA=projectDA;
    _身份=身份;
    }
    
    public IEnumerable将是一个问题。IMHO上下文不应该知道任何关于如何访问它的信息。您应该有一个中间层/逻辑层,该层支持租户应用逻辑(而不是数据层)。因此,我需要在稍后阶段应用查询过滤器,即在用户身份验证之后?是否有任何指针可以从中间层/逻辑层方法开始?感谢Naveddeshmukh,我的第1部分工作正常。只是命名不同,我的租户是OrganizationID,博客实体是项目实体。如果我指定了int per,这将非常有效上面是我的示例。但是,我正在处理第2部分。在实例化dbContext时,我不知道如何传入OrganizationID。OrganizationID可以作为声明(aspnet标识)使用,但我找不到
    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; }
      }
    }