仅从登录用户编辑信息

Edit Information only from the logged user

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

我正在使用以下途径编辑信息: Company/1/Store/3/Product/4/Edit

如何确保不属于该公司的用户不会更改 url 上的 ID 并更改其他公司的信息? 我已经在登录时存储了用户 companyId,因此我可以在 Stores Controller 上执行此验证,因为我知道 Store 有一个关联的 CompanyId,我只是检查该 companyId 是否等于登录的用户 CompanyId。但现在从产品上看,我与公司本身没有任何关联,只与商店有关。

我的问题是,我应该创建一个 属性 CompanyId 还是 UserId 来在商店 table 上创建该产品,或者我应该在查询中使用连接并说 db.Store.Find(UrlStoreId).Include(Products).FirstOrDefault(o => o.CompanyId == loggedUserCompanyId);

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

提前致谢。

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

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

给定一个 URL: Company/1/Store/3/Product/4/Edit

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

这会将您的域强制执行到公司和商店的层次结构,以确保有人不会尝试 "tweak" 诸如商店 ID 或产品 ID 之类的东西来访问另一家公司的数据。如果您有一个 API 调用,例如 /Product/4/Edit 那么您应该始终确保您的身份验证令牌中的声明包含足够的信息(CompanyId)以确保您可以验证 API 调用产品 ID 4 属于正确的公司。

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

其他选项包括在数据库级别强制执行授权,我相信这个选项在 SQL 服务器中可用,其中公司数据可以单独分区。据我所知,这将涉及数据库服务器中每个租户的单独用户帐户。一种手动风格是采用类似“每个租户模式”或“每个租户数据库”之类的东西,以确保数据不会在租户之间公开。