Spring Data Rest安全HATEOAS链接

时间:2016-02-12 14:03:43

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

假设我有一个User实体,其ManyToMany实体映射到UserGroup。如果我为两个实体创建存储库并获取URI /users/1,我会得到这样的响应:

{
  "enabled" : true,
  "password" : "xxxxxx",
  "username" : "xxxxxx",
  "credentialsNonExpired" : true,
  "accountNonLocked" : true,
  "accountNonExpired" : true,
  "_links" : {
    "self" : {
      "href" : "http://127.0.0.1:45950/users/1"
    },
    "user" : {
      "href" : "http://127.0.0.1:45950/users/1"
    },
    "userGroups" : {
      "href" : "http://127.0.0.1:45950/users/1/userGroups"
    }
  }
}

此处的userGroups链接非常有用。

我可以使用UserGroup端点列出所有/userGroups。 我想使用不同的/userGroups表达式来保护/users/1/userGroups端点和spring-security端点。

在此处使用引用:http://docs.spring.io/spring-data/rest/docs/current/reference/html/#security我了解如何保护第一个端点:

public interface UserGroupRepository extends PagingAndSortingRepository<UserGroup, Long> {

    @PreAuthorize("hasRole('ROLE_ADMIN')")
    @Override
    Iterable<T> findAll();
}

但是如何保护第二个端点?这可能是目前的吗?是否有一些工作计划在这样的功能。我很想做出贡献。

2 个答案:

答案 0 :(得分:1)

我也遇到过这个问题,但没有找到任何使用Spring安全注释的解决方案。作为一种解决方法,我添加了以下内容:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        // Whatever config you already have.
        .authorizeRequests()
            .antMatchers("/users/*/userGroups").hasRole("ADMIN");
}

我对WebSecurityConfigurerAdapter的实施。虽然这有效,但它重复了保护存储库时所做的工作,并且在添加新存储库时很容易忘记添加java配置和注释。

答案 1 :(得分:0)

我意识到这个问题已有四年了,但是这个问题一直困扰着我,我终于找到了行之有效的方法。

从本质上说,问题在于Spring HATEOAS没有真正的安全控制;虽然您可以使用适当的方法级安全注释配置存储库以防止通过REST API进行访问,但是您不能阻止HATEAOS表示模型汇编器对它可以看到的任何对象进行处理。

我发现的解决方案是为RepresentationModelProcessor公开一个EntityModel<DomainObject> bean。就您而言,这看起来像是

@Configuration
public class SecureHateoasConfig {

    public static class UserGroupProcessor implements RepresentationModelProcessor<EntityModel<UserGroup>> {
        @Override
        public EntityModel<UserGroup> process(EntityModel<UserGroup> model) {
            if(SecurityContextHolder.getContext()
                .getAuthentication()
                .getAuthorities()
                .stream()
                .map(GrantedAuthority::getAuthority)
                .anyMatch("ROLE_ADMIN"::equals)) {
                return model;
            } else {
                return null;
            }
        }
    }

    @Bean
    public UserGroupProcessor userGroupProcessor() {
        return new UserGroupProcessor();
    }

}

null替换的对象似乎在正常处理后被过滤掉了,因此嵌入式实体根本不包括与过滤器不匹配的对象!

如果只进行基于角色的安全性,可能有一种更简单的方法来过滤链接,但是恐怕我不知道...

当然,可以扩展此范围,因为您的安全对象处理器不仅需要应用于EntityModel<UserGroup>!在我的情况下,我有一个接口,我所有的安全域对象实现都可以用来制定安全性决策,因此只需要一个RepresentationModelProcessor实现/ bean。