Java 如何防止客户端更改Google云端点中的objectify@ID

Java 如何防止客户端更改Google云端点中的objectify@ID,java,rest,google-cloud-datastore,google-cloud-endpoints,objectify,Java,Rest,Google Cloud Datastore,Google Cloud Endpoints,Objectify,我正在使用objectify将对象持久化到Google云数据存储。“主键”用@Id注释 @Entity class Car { @Id Long id; ... } 我生成客户端端点(使用Android Studio) 我需要所有字段的getter和setter,包括id,以便REST能够序列化和反序列化对象。如果我没有添加getter和setter,那么它们是由googleendpointbuilder创建的 通常,客户机从数据存储中获取实例,更改属性并将其更新回来。后端处理

我正在使用objectify将对象持久化到Google云数据存储。“主键”用@Id注释

@Entity
class Car {
    @Id Long id;
    ...
}
我生成客户端端点(使用Android Studio)

我需要所有字段的getter和setter,包括id,以便REST能够序列化和反序列化对象。如果我没有添加getter和setter,那么它们是由googleendpointbuilder创建的

通常,客户机从数据存储中获取实例,更改属性并将其更新回来。后端处理新属性并将其存储在数据存储中

只要id是相同的,它就可以正常工作。但是当客户端更改id时会发生什么?因为服务器是无状态的,所以它认为另一个对象已被更新,并且插入或更新了错误的对象。换句话说,如果新id已经存在于数据存储中,则更新该记录;如果它不存在,则创建具有该id的新记录

这种行为是数据存储所固有的,但如果客户端更改id,这将使数据库混乱,因此必须有一种方法来防止这种情况

我可以看到两种解决方案:

  • 正如@zgc7009在这里所建议的,我可以将setter留空,让它什么也不做。我已经试过了,只要没有相关的对象,它就行

  • 我可以在后端使用一个version字段,每次调用UPDATE时都会增加这个字段。这允许我验证客户机版本==服务器版本-1,如果不是,则抛出异常。此措施将减少更新错误记录的机会,但它需要在每次写入之前从数据存储中读取数据,因此效率不高

  • 由于这两种解决方案都不好,我相信谷歌的某些人已经在考虑这一点,必须有更好的方法确保REST中的数据完整性。根据我的理解——我不知道这是否可以改变——Google Endpoints API是以一种不包含URL中id的方式生成的,或者是在封面下生成的。换句话说:通常存储对象的id包含在URL(元数据)中。这里,它包含在对象(有效负载)中,因此可以由客户端更改

    有人能解释一下吗


    PS:我知道上面示例中数据存储的最佳实践可能会使用VIN作为id,但这并不总是可能的。有些对象无法创建唯一标识符用作id。

    看起来像是许多人面临的常见问题。你可以做一件事:


    上面的解决方案2是一个很好的解决方案,但是您担心在每次写入之前从
    数据存储中读取数据。这可以通过使用
    @Cache
    注释实体类来缓解,以便客户端第一次检索实体时,它们将被缓存。这样,当客户端调用后端进行更新或执行任何操作时,在比较版本时,您将不会点击数据存储。

    如果您担心在端点上暴露敏感属性,您有两种选择:

    1) 使用
    @ApiResourceProperty(ignored=AnnotationBoolean.TRUE)注释它们(getter)
    以便端点序列化程序跳过它们


    2) 不要通过API发送您的实体,创建基本POJO,只包含您想要/需要传输的字段

    为什么客户端需要更改Id?你能想出一个很好的方案来解释为什么需要更改Id吗?客户永远不应该更改Id,但我的问题是如果它确实更改了Id会发生什么。它可以更改它,因为REST是无状态的,客户端可以更改任何属性。你如何防止某人做任何恶意的事情?所以我在上一篇文章中不清楚。rest格式是简单的字符串。getter的出现/缺席并不能阻止任何人更改ID。这是一种安全错觉。服务器必须确保权限,如果有人想写入坏数据,您需要找到隔离帐户损坏的方法或进行安全检查。