Spring Data Rest 仅使用父路径

Spring Data Rest only use path with parent

简短描述:我希望 spring-data-rest 只生成像“/users/{userId}/settings”、“/users/{userId}/values”这样的端点,而不是“/settings” " 或 "/值"。

更多详情:

我开始对检查每个控制器函数是否已登录用户有权访问所请求的资源以及是否有以下想法来自动化它感到恼火(如果有人有更好的想法不会导致以下问题,我很乐意听到)

在我的应用程序中,用户只能访问自己的资源,不能看到其他用户的任何数据。

所以我的想法是限制(使用网络安全配置)所有以“/users/{id}**”开头的路径,只允许在登录用户具有给定 ID 时进行访问。 这样,如果我的端点是“/用户/{userId}/userValues” 或“/users/{userId}/settings”等。由于权限规则

,每个用户只能访问自己的数据

为了进一步自动化该过程并确保我不会忘记在控制器中检查 userId,我尝试使用 spring-data-rest,除了一个问题外它很棒:

spring-data-rest 为每个对象生成一个 API-endpoint。它们看起来像这样:
“/设置”、“/用户”、“/值”。

我想要的路径也生成了:“/users/{userId}/values”和“/users/{userId}/values”,它正确地检查了 userId,所以我的想法在原则上似乎可行.

但是我不知道如何禁用路径以子项(“/settings”、“/values”)开头的端点,因为我只想要以“/users/{ userId}”可用。

这可能吗?或者有没有更好的方法来实现用户只能查看和编辑自己的数据?

这是我用于测试此场景的项目的 类(我知道命名很糟糕,如果我知道我可以完成此工作,我将设置一个新项目,这仅用于测试):

Gradle 依赖关系:

dependencies {
    compile("org.springframework.boot:spring-boot-starter")
    //web frontend
    compile("org.springframework.boot:spring-boot-starter-web")
    //rest endpoint generator
    compile("org.springframework.boot:spring-boot-starter-data-rest")
    //database connection
    compile("mysql:mysql-connector-java")
    compile("org.springframework.boot:spring-boot-starter-data-jpa")
    //Swagger (/v2/api-docs)
    compile("io.springfox:springfox-swagger2:2.9.2")
    //pretty swagger (/swagger-ui.html)
    compile("io.springfox:springfox-swagger-ui:2.9.2")
    //Lombok (automatic getter / setter)
    compile("org.projectlombok:lombok:1.18.6")
}

用户:

@Entity
@Getter
@Setter
public class User {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Integer id;

  private String firstName;

  private String lastName;

  @OneToMany(mappedBy="user", cascade= CascadeType.ALL)
  private List<UserValue> values;

  @OneToOne
  @RestResource(path = "settings", rel = "SettingsRel")
  private Settings settings;
}

用户值:

@Entity
public class UserValue {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  Integer id;

  String value;

  @ManyToOne
  @JoinColumn(name = "user_id")
  @JsonIgnore
  private User user;

  public Integer getId() {
    return id;
  }

  public void setId(Integer id) {
    this.id = id;
  }

  public String getValue() {
    return value;
  }

  public void setValue(String value) {
    this.value = value;
  }

  public User getUser() {
    return user;
  }

  public void setUser(User user) {
    this.user = user;
  }
}

设置:

@Entity
@Getter
@Setter
public class Settings {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  Integer id;

  private HashMap<String, Object> settings;
}

用户值存储库:

public interface UserValueRepository extends CrudRepository<UserValue, Integer> {
}

用户资料库:

   public interface UserRepository extends CrudRepository<User, Integer> {
    }

设置存储库:

  public interface SettingsRepository extends CrudRepository<Settings, Integer> {
    }

我在使用 spring-data-rest 时遇到的另外两个问题是它似乎不适用于 Swagger 和 Lombok。所以我对实现目标的其他方式更加开放

所以关于我原来的问题:有两种方法可以实现禁用不以“/users/{userId}”开头的路径:直接在 WebSecurityConfigurerAdapter 中禁用它或使用过滤器。我使用了一个过滤器,例如将请求“/settings”转发到“/users/{idOfLoggedInUser}/settings”,这一切都非常适合 GET-Request。

然而,spring-data-rest 似乎只处理 POST 和 PUT 请求对象的根路径,所以 while GET("/users/{userId}/settings ") 没有问题,如果你想 POST 它需要是 "/settings" 并且不能自动绑定到用户。

看来还是得自己手动写Controller了

然而,我仍然找到了一个更优雅的解决底层身份验证问题的方法,而不是手动从数据库中选择正确的用户,然后在 Spring 中使用 @PreAuthorize 和 @PostAuthorize 在给定对象上设置该用户。这两个概念对我来说仍然有点棘手,但它们可以完成工作,并且稍后将以非常好的方式扩展为 "friends can also see data if you gave them access" 或类似的规则。