Spring Data REST:一个实体的多个端点

时间:2015-10-09 13:47:21

标签: spring-security spring-data spring-data-rest

前提:
Web服务通过REST公开其数据。每条记录都属于创建记录的用户(行级安全性)。用户只能检索自己的记录。

@RepositoryRestResource(path = "talks")
public interface TalkRepository extends PagingAndSortingRepository<Talk, Long> {

    @Override
    @Query("select t from Talk t where t.owner.id= ?#{principal?.id}")
    Page<Talk> findAll(Pageable pageable);
}

该存储库现在可在/talks端点下使用。

问题:
有没有办法1)在多个端点公开相同的域实体,2)根据端点定义不同的@Query注释?

  • /talks
    我想让它成为我对管理员角色开放的默认实现
  • /me/talks
    这是对主体应用行级安全性的端点,并且/me/**端点的一部分作为公共api公开给实现客户端。

此问题与https://jira.spring.io/browse/DATAREST-555部分相关,但仅限于目前尚未支持其他路径段。

理由:
我喜欢不必将过多的条件逻辑放入像is owner or has_some_role这样的SPeL查询(一些例子here)。此外,通过与默认API不同的策略保护/me/**端点变得容易(例如,只有/me/**可能受OAuth2限制。)

2 个答案:

答案 0 :(得分:2)

如果您了解更好/更简洁的解决方案,我很乐意接受其他答案。

基于@OliverGierke的建议,official docs和其他各种SO答案(也几乎完全由Oliver提出,大部分是123)我有实现了一个自定义控制器来为端点提供服务。

这也可以在自定义端点上进行投影,并使用Spring Data REST的HATEOS汇编程序提供HAL+JSON输出。到目前为止我还没有做过的工作是如何重用SDR提供的配置文件和alps逻辑,但在自定义控制器中丢失。

@BasePathAwareController
public class MyTalksController {

    private final TalkRepository repository;
    private final PagedResourcesAssembler pagedResourcesAssembler;

    @Autowired
    public MyTalksController(TalkRepository repo, PagedResourcesAssembler assembler) {
        repository = repo;
        pagedResourcesAssembler = assembler;
    }

    @RequestMapping(method = RequestMethod.GET, value = "/me/talks")
    @ResponseBody
    public PagedResources<?> getTalks(Pageable pageable, PersistentEntityResourceAssembler entityAssembler) {
        Page<Talk> talks = repository.meFindAll(pageable);
        return pagedResourcesAssembler.toResource(talks, entityAssembler);
    }
}

答案 1 :(得分:0)

正在回答1)—是的,可能如下:

// skipping old requests for the sake of the backward compatibility with the clients
// just returning ok with HTTP status 200
@RequestMapping(method = {RequestMethod.GET, RequestMethod.POST, RequestMethod.OPTIONS, RequestMethod.DELETE},
                value = {"/lock", "/configure", "/cancel", "/initialize", "/register"})
public ApiResponse ok() {
    return ApiResponse.success();
}

回答2)-不同的查询逻辑自然会适合不同的端点,因此我认为有必要为每个端点创建相应的方法。