Asp.net 仅编辑来自已登录用户的信息

Asp.net 仅编辑来自已登录用户的信息,asp.net,asp.net-mvc,entity-framework,database-design,identity,Asp.net,Asp.net Mvc,Entity Framework,Database Design,Identity,我有以下表格:公司1->*商店1->*产品 我使用以下途径编辑信息: 公司/1/商店/3/产品/4/编辑 if(loggedInUserCompanyId != urlCompanyId) // Dump session, kick out. var product = context.Companies .Where(c=> c.CompanyId == urlCompanyId) .SelectMany(c=> c.Stores.Where(s=> s.Sto

我有以下表格:公司1->*商店1->*产品

我使用以下途径编辑信息: 公司/1/商店/3/产品/4/编辑

if(loggedInUserCompanyId != urlCompanyId)
  // Dump session, kick out.

var product = context.Companies
  .Where(c=> c.CompanyId == urlCompanyId)
  .SelectMany(c=> c.Stores.Where(s=> s.StoreId == urlStoreId)
     .SelectMany(s => s.Products))
  .SingleOrDefault(p => p.ProductId == urlProductId);
我如何确保不属于此公司的用户不会更改url上的ID,也不会更改其他公司的信息? 我已经在登录时存储了用户companyId,因此我可以在Stores Controller上执行此验证,因为我知道某个商店有一个关联的companyId,我只需检查该companyId是否等于登录的用户companyId。但现在从产品来看,我与公司本身没有任何关联,只是与商店有关联

我的问题是,我应该在stores表上创建创建该产品的属性CompanyId或UserId,还是应该在查询中使用连接,比如db.Store.Find(UrlStoreId).Include(Products.FirstOrDefault(o=>o.CompanyId==loggedUserCompanyId)

我想知道应用程序中这类问题的约定


提前感谢。

对于MVC控制器,可以在会话状态下记录当前会话的用户CompanyId,并与每次呼叫进行比较。如果由于任何原因ID不匹配,则转储用户会话并将其返回登录屏幕。对于Web API控制器,您应该在Auth令牌的声明中包含CompanyId以执行相同类型的验证。同样,如果发现不匹配,则应记录违规尝试并使令牌无效(如果支持)

至于连接,如果您在实体之间设置引用,那么您应该能够始终强制执行ID

给定一个URL,其中包含: 公司/1/商店/3/产品/4/编辑

if(loggedInUserCompanyId != urlCompanyId)
  // Dump session, kick out.

var product = context.Companies
  .Where(c=> c.CompanyId == urlCompanyId)
  .SelectMany(c=> c.Stores.Where(s=> s.StoreId == urlStoreId)
     .SelectMany(s => s.Products))
  .SingleOrDefault(p => p.ProductId == urlProductId);
这将强制您的域到公司和商店的层次结构,以确保有人不会试图“调整”商店ID或产品ID之类的内容来访问另一家公司的数据。如果您有一个API调用,如/Product/4/Edit,那么您应该始终确保您的身份验证令牌中的声明包含足够的信息(CompanyId),以确保您可以验证产品Id 4的API调用是否属于正确的公司

为了确保数据受到限制,您肯定可以/应该做更多的工作,但这应该为您提供一个最小的起点。理想情况下,您希望在代码结构中进行尽可能深入的授权检查,以确保不会遗漏此类检查。我倾向于使用repository模式来包装对DbContext的调用,而不是让控制器等直接访问上下文。这样,即使我的存储库返回IQueryable,它们也会强制执行授权,以便控制器代码搜索数据时不必担心忘记包含“公司”检查


其他选项包括在数据库级别强制执行授权,我认为在SQLServer中可以使用该选项,在SQLServer中,公司数据可以单独分区。AFAIK这将涉及数据库服务器中每个租户的单独用户帐户。这方面的一种手动风格是采用类似“每个租户模式”或“每个租户数据库”的方式,以确保租户之间不会暴露数据。

您好,Steve Py,谢谢您的回答,您所说的一切听起来都很棒。数据库的授权对我来说是新的,我很快就会看一看。我仍然没有使用存储库和工作单元,只是因为我仍然在开发项目,现在不需要它。我还有一个问题,如果我的路径是“Manage/{storeId]/Product/{productId},我如何在Url上没有公司ID的情况下执行此验证?这实际上是我现在的路径,我刚才的问题把我搞砸了。我应该在Url上包含公司、更改数据库结构还是使用include?