我正在建立a previous discussion I had with Jon Skeet。
我的方案的要点如下:
此时,我理解使用客户端生成的UUID作为数据库中对象的PK是不好的做法。原因是恶意用户可以修改生成的UUID并强制在我的数据库上发生PK冲突。
为了减轻因在PlaylistItem上强制PK冲突而导致的任何损害,我选择将PK定义为两个ID的组合 - 客户端生成的UUID和服务器生成的GUID。服务器生成的GUID是PlaylistItem的播放列表ID。
现在,我一直在使用这个解决方案,但我不明白为什么/相信我的解决方案比简单地信任客户端ID更好。如果用户能够强制PK collison与另一个用户的PlaylistItem对象,那么我认为我应该假设他们也可以提供该用户的PlaylistId。他们仍然可以强迫对手。
所以......是的做这样的事情的正确方法是什么?允许客户端创建UUID,服务器在成功保存时会竖起大拇指。如果发现冲突,请恢复客户端更改并通知检测到的collison?
答案 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并且客户端不提供这个,否则显然不安全