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

Posted

技术标签:

【中文标题】如何按角色限制对 Spring Data REST 投影的访问?【英文标题】:How to restrict access by role to a Spring Data REST projection? 【发布时间】:2016-02-13 05:01:04 【问题描述】:

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

@Entity
public class Person 

   @Id @GeneratedValue
   private int id;

   private String name;

   @JsonIgnore
   private String superSecretValue;

   ...


我们希望 Spring Data REST 公开该实体的所有字段,除了 superSecretValue,因此我们使用 @JsonIgnore 注释了该字段。

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

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

   String getName();
   String getSuperSecretValue();


太棒了。所以现在我们可以像这样访问Person 实体包括 superSecretValue 字段:

curl http://localhost:8080/persons?projection=withSecret

我的问题是我们如何才能确保投影?我们如何配置东西,以便任何人都可以检索Person 实体没有 superSecretValue 字段...但只有具有特定角色(例如,ROLE_ADMIN)的人才能使用投影来检索隐藏的领域?

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

【问题讨论】:

这个问题之前已经问过 - ***.com/questions/28794145/… - 我认为你尝试做的事情不受支持。另外我会质疑你是否应该这样做 - 投影只是对数据的不同看法,在这里引入安全性听起来不正确。我会为此实现一个自定义控制器方法并保护它。 @MathiasDpunkt:假设您确实编写了一个自定义控制器方法...返回类型为Person,并应用@ResponseBody 注释使其序列化为JSON。在这种情况下,由于@JsonIgnore 注释,superSecretValue 字段仍将被省略。那么,您会在该字段上手动将Person 实体转换为基本相同的DTO 类without @JsonIgnore?您是否会实现自己的自定义 Jackson 序列化程序并自己构建 JSON 而不是依赖@ResponseBody?另一种方法? @MathiasDpunkt:在某些领域需要基于角色的可见性似乎必须是一个不太不寻常的用例。授予对存储库 CRUD 方法的基于角色的访问权限非常简单,但授予基于角色的实体字段可见性却如此繁琐,这很奇怪。只是想找出阻力最小的路径。 别误会我的意思——我不认为你的要求有问题。但我认为您尝试对其建模的方式可能需要一些考虑。如果superSecretValue 在安全性方面与其他人的属性如此不同,那么它可能根本不属于该人。如果您将此值建模为一个单独的实体会怎样。然后,您可以提供具有适当授权规则的单独存储库,并且只有授权用户才能遍历从人员到秘密值的关系。 哦,我很尴尬,我没有想到这一点。 @OneToOne 代理实体,具有不同的访问级别。这不是 100% 理想的,但可以完成工作。 【参考方案1】:

您可以使用带有条件 SpEL 表达式的 @Value 重载投影中的属性 - 就像在这个 already answered similar question 中一样。

考虑其他替代方案(其他已经提到的):

    模型重构。按访问逻辑拆分实体(例如Person Account) 为特殊逻辑和访问检查添加自定义端点。例如,“/people/me”的当前用户。 自定义标准端点。例如,为“/people”、“/people/id”添加自定义控制器,它将根据用户权限预处理并返回自定义Resource类型(DTO)(例如返回PublicPerson而不是Person)。然后,您可以编写自定义资源处理器,为这些类型添加自定义链接和自定义投影。

另请参阅:spring-data-rest DATAREST-428 中有关此主题的问题。

【讨论】:

【参考方案2】:

你可以试试这个解决方案:https://***.com/a/35399030/679240

@Projection(name = "detailed", types = User.class)
public interface UserDetailProjection extends UserSimpleProjection

    @Value("#@userService.checkAccess(target)? target.email : null")
    public String getEmail();

【讨论】:

以上是关于如何按角色限制对 Spring Data REST 投影的访问?的主要内容,如果未能解决你的问题,请参考以下文章

Spring Data Rest - 按多个属性排序

如何让Spring的Data Rest Repository按名称而不是id来检索数据

在 Spring Data rest json Response 中动态过滤实体字段

如何在 Spring-Boot-REST 调用中获取用户信息?

Spring data rest - 有没有办法限制支持的操作?

Spring Data Rest - 按嵌套属性排序