【发布时间】:2016-11-30 19:24:46
【问题描述】:
场景: (使用 ASP.NET Web 应用程序 - Core 或 MVC)
我有一个数据库,每个用户都有Users 和Items。
这意味着UserId 是foreign key 在Items 表中。
我在浏览器中以User 的身份登录。我将Items 作为ItemViewModels 的列表,通过一个简单的api GET 请求映射(AutoMapper)到ItemViewModels。
我想通过一个简单的 API 调用更新其中一个项目(应该属于我 - 已登录的用户)。因此,我通过 PUT 请求将修改后的项目作为 ItemViewModel 发送回服务器。
第一种方法:
最简单的方法是在 ItemViewModel 中包含项目的数据库 ID ItemId - 所以当我收到要更新为 ItemViewModel 的项目时,我可以将其映射回现有项目数据库。
但这对我来说听起来很不安全,因为任何人都可以使用任何ItemId 修改 PUT 请求并影响不属于执行请求的用户的项目。我对这种方法有什么遗漏吗?
第二种方法:
不要在ItemViewModel 中传递数据库PK ItemId。
而是使用其他形式的标识:假设用户 X 有 10 个项目。它们使用名为UserItemId(也存在于数据库中)的属性从1 到10 编号。
然后我可以在ItemViewModel 中传递这个UserItemId,当我取回它时,我可以将它映射到数据库中的现有项目(如果请求一切正常)或丢弃它并拒绝请求,如果UserItemId 与登录用户项目中的任何内容都不匹配。
有人使用这种方法吗?
优点:
用户只能访问自己的项目,不能影响其他任何人,因为它不知道实际的项目 ID(主键),并且任何修改都仅限于自己的项目。
缺点:
必须在服务器端实施大量额外管理才能使这种方法发挥作用。
还有其他方法吗?
请考虑上面提到的情况适用于数据库中客户端实现可以 CRUD 的所有实体,所以它不仅仅是上面描述的简单情况。
建议的解决方案应该适用于整个应用数据。
我知道有人问过这个问题 here 和 here 但第一个问题没有令人满意的答案,我认为第二个问题并不真正适用于我的情况,因为它只涉及 UserId .
谢谢。
编辑
请将上面的Item 视为一个聚合根,其中包含多个复杂的subItems,每个在数据库中都有一个表。这个问题适用于他们和主要的Item。这意味着每个 subItem 都作为 ViewModel 传递给客户端。
我应该提到关于进一步保护更新请求:
对于第一种方法,我可以轻松检查是否允许用户更改项目。但我也应该为所有
subItems这样做。对于第二种方法,我可以检查用户是否可以更新
Item,如下所示:我得到传入 ViewModel 的userItemId-> 我从数据库中获取所有登录用户的项目并尝试找到与相同userItemId匹配的匹配项,如果我成功了,我会继续更新。
【问题讨论】:
-
永远不要相信用户输入。您必须始终在服务器上进行验证。检查当前用户是否有权根据 ID 更新对象,如果有,则执行更新(否则重定向到错误页面)
标签: asp.net-mvc security model mapping viewmodel