Spring Data Rest中的存储库访问控制基于用户主体

时间:2015-04-17 00:25:00

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

我正在尝试实现细粒度访问控制,同时仍然利用Spring数据休息。

我正在努力保护CrudRepository,因此用户只能修改或插入属于他们的数据。我正在使用@PreAuthorize / @PostAuthorize@PreFilter / @PostFilter来锁定当前主体的访问权限。

到目前为止,我的存储库看起来像这样。

public interface MyRepository extends CrudRepository<MyObject, Integer> {

    @PreAuthorize("#entity.userId == principal.id")
    @Override
    <S extends MyObject> S save(S entity);

    @PreFilter("filterObject.userId === principal.id")
    @Override
    <S extends MyObject> Iterable<S> save(Iterable<S> entities);

    @PostAuthorize("returnObject.userId == principal.id")
    @Override
    MyObject findOne(Integer integer);

    @PostFilter("filterObject.userId == principal.id")
    @Override
    Iterable<MyObject> findAll();

}

虽然这有点单调乏味,但它似乎完成了我所追求的目标。 (如果有人知道更好的方式,请随时告诉我!)

我遇到问题的地方是delete()count()exists()

    @Override
    long count();

    @Override
    void delete(Integer integer);

    @Override
    void delete(MyObject entity);

    @Override
    void deleteAll();

    @Override
    boolean exists(Integer integer);

这些方法要么使用Integer ID参数,要么根本不带参数。看来我必须首先选择具有输入ID的实体,然后执行auth检查。

这种类型的授权是否可以在存储库中进行?

由于

编辑:

感谢ksokol,现在似乎正在运作。

我向@Configuration

添加了一个新bean
@Bean
public EvaluationContextExtension securityExtension() {
    return new SecurityEvaluationContextExtensionImpl();
}

此bean扩展EvaluationContextExtensionSupport并覆盖getRootObject以返回保存我的自定义主体的SecurityExpressionRoot

public class SecurityEvaluationContextExtensionImpl extends EvaluationContextExtensionSupport {
@Override
public String getExtensionId() {
    return "security";
}

@Override
public Object getRootObject() {
        Authentication authentication =   SecurityContextHolder.getContext().getAuthentication();
        return new SecurityExpressionRoot(authentication){};
    }
}

2 个答案:

答案 0 :(得分:18)

Spring Security 4.0开始,您可以访问Spring Data JPA查询中的安全上下文。

SecurityEvaluationContextExtension bean添加到bean上下文中:

@Bean
public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
    return new SecurityEvaluationContextExtension();
}

现在,您应该能够在Spring Data查询中访问Principal

@Query("select count(m) from MyObject as m where m.user.id = ?#{ principal?.id }")
@Override
long count();

@Modifying
@Query("delete from MyObject as m where m.id = ?1 and m.user.id = ?#{ principal?.id }")
@Override
void delete(Integer integer);

@Modifying
@Query("delete from MyObject as m where m.id = ?1 and m.user.id = ?#{ principal?.id }")
@Override
void delete(MyObject entity);

@Modifying
@Query("delete from MyObject as m where m.user.id = ?#{ principal?.id }")
@Override
void deleteAll();

@Query("select 1 from MyObject as m where m.id = ?1 and m.user.id = ?#{ principal?.id }")
@Override
boolean exists(Integer integer);

注意。查询可能有错误。我没时间测试它。

答案 1 :(得分:2)

也可以通过在自定义Spring存储库事件处理程序中实现检查来实现。请参阅@HandleBeforeCreate@HandleBeforeUpdate@HandleBeforeDelete

或者,您可以使用基于权限的表达式,例如使用ACL或您的自定义ACL,您可以编写@PreAuthorize("hasPermission(#id, 'MyObject', 'DELETE')")