排除 Spring-data-rest 资源的部分字段

Posted

技术标签:

【中文标题】排除 Spring-data-rest 资源的部分字段【英文标题】:Exclude some fields of Spring-data-rest resource 【发布时间】:2015-04-04 00:48:45 【问题描述】:

我正在尝试将 Spring-data-rest 与 spring-data-mongodb 一起使用来公开只读资源。

我遇到的问题是我想对我的文档有不同的看法。 假设我在文档中有一些私人信息,我不想公开它们。

所以我尝试了几种方法。 我读了这篇 https://spring.io/blog/2014/12/02/latest-jackson-integration-improvements-in-spring 的帖子,描述了如何使用 JsonView 来选择我们想要公开的字段。

我试过这样:

@RepositoryRestResource(collectionResourceRel = "recommandation", path =    "recommandations")
interface RecommandationRepository extends MongoRepository<Recommendation,   ObjectId> 

@Override
@JsonView(View.Public.class)
Iterable<Recommendation> findAll(Iterable<ObjectId> objectIds);
... // other find methods

它不起作用。然而,在 cmets 中说:https://spring.io/blog/2014/12/02/latest-jackson-integration-improvements-in-spring#comment-1725671983 答案建议使用@Projections 但是@Projections 会产生这样的网址:“…/recommandations?projection” 这意味着投影只是一个选项,因此仍然会暴露整个对象。

这里描述了另一种方法https://github.com/spring-projects/spring-data-rest/wiki/Configuring-the-REST-URL-path 它建议对我们不想公开的字段使用 @RestResource(exported = false) 注释。

但它不灵活。如果我想公开一个公共的只读 API 和一个私有的完全访问 API。不能按 api 禁用此注解。

还有其他建议吗?

【问题讨论】:

如何区分公共 API 和私有 API?同一个类有两个存储库吗?那么两节课怎么样? 【参考方案1】:

重要的一点是 Spring Data REST 使用基于域对象的 Jackson 序列化参数,而不是存储库定义。隐藏特定字段以免出现在 JSON 中的一种简单方法如下:

@Entity
public class User 

    @Id @GeneratedValue
    private Long id;

    private String name;

    @JsonIgnore
    private String password;
    ...

在此示例中,无论如何使用此实体,我的用户对象都不会导出密码字段。 Jackson 支持将这个放在场上,或者放在相应的 getter 方法上。

当您将 @JsonIgnore 放入域模型中时,它会使其成为默认定义。投影是更改渲染哪些字段的选项。看下面的例子:

@Projection(name = "noImages", types = Item.class)
public interface NoImages 

    public Link gethtmlUrl();


这个项目只能在渲染 Item 域对象时使用。它不是默认视图,而是通过 ?projection=noImages 使用的选项。但不要忘记:当应用 Jackson 序列化时,项目将覆盖领域模型的设置。这意味着您可以为上面的 User 对象编写一个投影,并让它包含 String getPassword()。这将覆盖域模型的默认设置,进而导出密码。责任在你。

最后一件事。 Spring Data REST 支持 Excerpt Projections。最常见的用例是您有一个与 Address 对象相关的 Customer 对象。默认情况下,查看客户地址的关系将显示要导航的 URI。但是,如果您一直想要地址信息,您可以通过创建一个呈现地址详细信息的投影来避免这种额外的 GET 操作。然后您可以为 Customer 对象配置它,默认打开此投影,并在您获取客户记录时基本上内联地址详细信息。

我意识到参考文档在所有这些细节上都不是最新的。您可以跟踪我们的进度以适当地更新文档,如下所示:

https://jira.spring.io/browse/DATAREST-449 https://jira.spring.io/browse/DATAREST-450 https://jira.spring.io/browse/DATAREST-451 https://jira.spring.io/browse/DATAREST-452 https://jira.spring.io/browse/DATAREST-453 https://jira.spring.io/browse/DATAREST-454

还有一个错误,即来自 Spring Data REST 的 ALPS 元数据还需要过滤掉带有 @JsonIgnore 标记的域字段(参见 https://jira.spring.io/browse/DATAREST-463)

附: @RestResource 已弃用,并且不是设置导出哪些字段的推荐方法。相反,请使用 @JsonIgnore,如前所示。

【讨论】:

@JsonIgnore 从响应中完全删除字段。如何返回只读字段作为响应,但只是让它们更新? 这是一个 Jackson 配置问题:有关详细信息,请参阅 this question。 如果我需要一个内部表示(允许显示和修改这个字段)和一个根本不想显示这个字段的公共只读表示,@JsonIgnore 不会帮助我对?它将删除两种表示的字段,不? 我有类似的要求来动态隐藏弹簧数据休息响应中的删除字段。想知道我们是否可以通过 Jackson 模块为某些实体挂钩 @jsonfilter 以使用 spring 数据休息 @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)【参考方案2】:

根据@johannes-rudolph 的建议...

考虑将此设置应用于字段(或属性,如果您从访问器进行映射):

@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)    
private String password;

这就是访问值所暗示的:将关联的字段标记为只写。因此该值可以设置,但不能通过 Jackson/JSON 序列化形式检索。

【讨论】:

以上是关于排除 Spring-data-rest 资源的部分字段的主要内容,如果未能解决你的问题,请参考以下文章

是否有适用于 JPA、spring-data、spring-data-rest 的通用 REST 查询语言

如何配置 Spring-Data-Rest 以仅返回登录用户拥有的数据

Mavne 排除 jar 包 中的目录文件和资源文件

Mavne 排除 jar 包 中的目录文件和资源文件

如何在 Spring-Data-Rest 中实现细粒度的访问控制?

Spring-Data-Rest 验证器