Java 如何按角色限制对Spring数据REST投影的访问?

Java 如何按角色限制对Spring数据REST投影的访问?,java,spring,rest,spring-data,spring-data-rest,Java,Spring,Rest,Spring Data,Spring Data Rest,在使用Spring数据JPA和Spring数据REST的应用程序中,假设您有这样一个实体类: @Entity public class Person { @Id @GeneratedValue private int id; private String name; @JsonIgnore private String superSecretValue; ... } curl http://localhost:8080/persons?projec

在使用Spring数据JPA和Spring数据REST的应用程序中,假设您有这样一个实体类:

@Entity
public class Person {

   @Id @GeneratedValue
   private int id;

   private String name;

   @JsonIgnore
   private String superSecretValue;

   ...

}
curl http://localhost:8080/persons?projection=withSecret
我们希望SpringDataREST公开该实体的所有字段,除了
superSecretValue
,因此我们用
@JsonIgnore
注释了该字段

但是,在某些情况下,我们确实希望访问
superSecretValue
,因此我们创建了一个投影,该投影将返回所有字段,包括该字段:

@Projection(name = "withSecret", types = {Person.class})
public interface PersonWithSecret {

   String getName();
   String getSuperSecretValue();

}
太棒了。现在我们可以访问
Person
实体,包括
superSecretValue
字段,如下所示:

@Entity
public class Person {

   @Id @GeneratedValue
   private int id;

   private String name;

   @JsonIgnore
   private String superSecretValue;

   ...

}
curl http://localhost:8080/persons?projection=withSecret
我的问题是我们如何确保该投影?我们如何配置事物,使任何人都可以检索
Person
实体,而无需
superSecretValue
字段。。。但是只有具有特定角色的人(例如,
role\u ADMIN
)才能使用投影来检索隐藏字段


我发现了无数使用
@PreAuthorize
@Secured
注释来保护Spring数据JPA存储库CRUD方法的例子(例如
save()
delete()
)。。。但是没有关于如何限制Spring数据REST投影使用的示例。

您可以使用带有条件SpEL表达式的
@Value
在投影中重载属性,如下所示

考虑其他备选方案(已提及的其他方案):

  • 模型重构。按访问逻辑划分实体(例如,
    账户
  • 为特殊逻辑和访问检查添加自定义端点。例如,当前用户位于“/people/me”
  • 自定义标准端点。例如,为“/people”、“/people/{id}”添加自定义控制器,该控制器将根据用户权限预处理并返回自定义
    资源
    类型(DTO)(例如,返回
    公共人员
    ,而不是
    人员
    )。然后,您可以编写自定义资源处理器,以便为这些类型添加自定义链接和自定义投影

  • 另请参阅:spring data rest中关于此主题的问题。

    您可以尝试以下解决方案:


    以前有人问过这个问题——我认为你试图做的事不受支持。此外,我想问你是否应该这样做——预测只是对数据的不同看法,在这里引入安全性听起来并不正确。我将为此实现一个自定义控制器方法并保护此方法。@MathiasdPunk:假设您确实编写了一个自定义控制器方法。。。返回类型为
    Person
    ,并应用
    @ResponseBody
    注释将其序列化为JSON。在这种情况下,由于
    @JsonIgnore
    注释,仍将省略
    superSecretValue
    字段。那么,您是否可以手动将
    Person
    实体转换为基本相同的DTO类,而该字段上没有
    @JsonIgnore
    ?您是否会实现自己的定制Jackson序列化程序,并自行构建JSON,而不是依赖
    @ResponseBody
    ?另一种方法?@MathiasDpunkt:似乎它必须是一个不太常见的用例,才能在某些字段上需要基于角色的可见性。授予对存储库CRUD方法的基于角色的访问是如此简单,授予实体字段的基于角色的可见性是如此繁琐,这相当奇怪。只是想找出阻力最小的途径。别误会我-我不认为你的要求有什么问题。但我认为,你尝试建模的方式可能需要一些考虑。如果
    superSecretValue
    在安全性方面与其他person属性不同,那么它可能根本不属于该person。如果将此值建模为一个单独的实体,该怎么办。然后,您可以提供一个单独的存储库,其中包含适当的授权规则,只有授权用户才能遍历从person到secret值的关系。具有不同访问级别的
    @OneToOne
    代理实体。这不是100%的理想,但可以完成工作。