Согласно Spring Data REST Documentation, метод POST создает новый объект из данного тела запроса. Однако я обнаружил, что он может также обновить существующий объект. В некоторых случаях это может быть проблематично. Вот пример:POST повторяющаяся запись, не вызывающая столкновение PK в Spring Data REST
DemoApplication.java
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
UserRepository.java
package com.example;
import org.springframework.data.repository.PagingAndSortingRepository;
public interface UserRepository extends PagingAndSortingRepository<User, String> {}
User.java
package com.example;
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class User {
@Id
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
pom.xml (в пределах проекта тэгом)
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
application.properties: пустые
URL: http://localhost:8080/users
Метод: POST
содержаниеJSON:
{"username":"user","password":"password"}
Я предположил выше, запрос POST получал HTTP 201 в первый раз , и только за один раз. Тем не менее, я смог отправить вышеупомянутый запрос POST много раз и получил HTTP 201 все время. Кроме того, я также смог изменить пароль в базе данных с помощью запроса POST.
Я считаю, что это проблема безопасности. Например, я могу разрешить анонимную регистрацию пользователя через запрос POST. Но, с вышеуказанной ситуацией, существующий пользователь может быть перезаписан.
Вопрос: Как я могу предотвратить новую сущность создаваемого из запроса POST, если старый объект уже существует с тем же идентификатором? Или я пропустил интерпретацию документа REST Spring Data?
Дополнительные пояснения:
Причиной этой проблемы является разработка позади Spring Data REST. Поскольку Spring Data REST построена на Spring Data JPA, который не использовался для непосредственного отображения на «вне». Таким образом, он «доверяет» данным, которые поступают. Метод isNew в org.springframework.data.repository.core.support.AbstractEntityInformation показывает, как данные определяются как новые или не новые.
public boolean isNew(T entity) {
ID id = getId(entity);
Class<ID> idType = getIdType();
if (!idType.isPrimitive()) {
return id == null;
}
if (id instanceof Number) {
return ((Number) id).longValue() == 0L;
}
throw new IllegalArgumentException(String.format("Unsupported primitive id type %s!", idType));
}
Результат метода isNew в конечном итоге эффект сохранения метода в org.springframework.data.jpa.repository.support.SimpleJpaRepository.
public <S extends T> S save(S entity) {
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
В ситуации, упомянутой в этом вопросе, поле имени пользователя, которое также идентификатор объекта пользователя, всегда будет содержать данные для создания новых пользователей. Поэтому, когда он переходит к isNew, id == null всегда возвращает false. Тогда метод save всегда будет выполнять операцию слияния.
Указанные выше подсказки - все, что я могу предоставить. Несмотря на это, я не знаю, есть ли решение для решения этой проблемы.
Ссылки на ссылки - это всего лишь ссылки. Они могут быть не точной версией того, что я использую.
Даже если это не PK/ID, вам все равно придется проверять до добавления/редактирования, чтобы поймать дубликаты. Правильно? Поэтому напишите валидатор. http://www.baeldung.com/spring-data-rest-validators –