为什么我不相信客户端生成的GUID?将PK视为客户端GUID和服务器GUID的组合可以解决任何问题吗?

时间:2013-04-08 22:59:11

标签: client-server primary-key client-side guid composite-key

我正在建立a previous discussion I had with Jon Skeet

我的方案的要点如下:

  • 客户端应用程序可以创建需要持久存储在数据库中的新“PlaylistItem”对象。
  • 用例要求以这样的方式创建PlaylistItem:客户端在显示PlaylistItem之前不必等待来自服务器的响应。
  • 客户端为PlaylistItem生成UUID,在客户端显示PlaylistItem,然后向服务器发出save命令。

此时,我理解使用客户端生成的UUID作为数据库中对象的PK是不好的做法。原因是恶意用户可以修改生成的UUID并强制在我的数据库上发生PK冲突。

为了减轻因在PlaylistItem上强制PK冲突而导致的任何损害,我选择将PK定义为两个ID的组合 - 客户端生成的UUID和服务器生成的GUID。服务器生成的GUID是PlaylistItem的播放列表ID。

现在,我一直在使用这个解决方案,但我不明白为什么/相信我的解决方案比简单地信任客户端ID更好。如果用户能够强制PK collison与另一个用户的PlaylistItem对象,那么我认为我应该假设他们也可以提供该用户的PlaylistId。他们仍然可以强迫对手。

所以......是的做这样的事情的正确方法是什么?允许客户端创建UUID,服务器在成功保存时会竖起大拇指。如果发现冲突,请恢复客户端更改并通知检测到的collison?

2 个答案:

答案 0 :(得分:3)

一个很好的解决方案如下:引用Sam Newman的"Building Microservices"

  

调用系统将POST一个BatchRequest,也许传入一个   可以放置所有数据的文件的位置。客户   service会返回一个HTTP 202响应代码,表示该代码   请求已被接受,但尚未处理。呼唤   然后,系统可以轮询资源,等待它检索201   已创建,表示已完成请求

所以在你的情况下,你可以POST到服务器,但立即得到像"我将保存PlaylistItem的响应,我保证它的ID将是这个#34;。然后,客户端(和用户)可以继续服务器(可能不是API,但是从API获得消息的一些后台处理器)花费时间来处理,验证并执行其他可能很重的逻辑,直到它保存实体。如前所述,API可以为该请求的状态提供GET端点,客户端可以轮询它并在出现错误时采取相应措施。

答案 1 :(得分:3)

可以信任服务器上的客户端生成的UUID或类似的全局唯一标识符。只是明智地做到这一点。

您的大多数表/集合也将拥有userId或能够通过FK将自己与userId关联。

如果您正在进行插入而恶意用户使用现有密钥,则插入将失败,因为记录/文档已存在。

如果您正在进行更新,则应验证登录用户是否拥有该记录或已获得授权(例如管理员用户)更新。如果正在实施纯所有权(即没有管理员用户方案),则查找记录/文档的where子句将包括Id和userId。从技术上讲,userId在where子句中是多余的,因为Id将唯一地找到一个记录/文档。但是,添加userId可确保记录属于进行更新的用户,而不是恶意用户。

我假设有一个加密的令牌或某种类型的会话,服务器正在解密以确定userId并且客户端不提供这个,否则显然不安全