【问题标题】:Relax Security for a Spring Data REST Projection放松 Spring Data REST 投影的安全性
【发布时间】:2015-04-19 05:06:30
【问题描述】:

我有一个 User 类,我想授权访问,这样只有用户才能看到他有权访问的内容。

使用 Spring Security 和 Spring Data Rest 很容易实现这一点,我在下面的 JPA Repository 中做了 -

public interface UserRepository extends JPARepository<User,Integer> {

    @PreAuthorize("hasRole('LOGGED_IN') and principal.user.id == #id")
    User findOne(@Param("id") Integer id);

}

这样,用户在访问 Spring Data REST 脚手架 URL 时就像 -

/users/{id}
/users/{id}/userPosts

只有使用 {id} 登录的人才能看到这些,而其他所有人都会像我想要的那样获得 401。

我的问题是我有一个 Projections,它是每个用户的公共视图,我正在使用 Spring Data Rest 投影创建它,如下所示,我希望每个 {id} 都可以访问它

@Projection(name = "details", types = User.class)
public interface UserDetailsProjection {
..
}

所以,/users/{id1}?projection=details/users/{id2}?projection=details 应该给出 200 OK 并显示数据,即使用户是通过 {id1}

登录的

我开始通过使用@PreAuthorize("permitAll") 标记投影来实现这一点,但这不会起作用,因为存储库有更严格的安全检查。我们可以在投影的地方拥有这个功能吗?我们可以放松安全性吗?

我正在使用最新的 Spring Data Rest 和 Spring Security 发行版

【问题讨论】:

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


    【解决方案1】:

    在数据访问层添加 spring 安全代码不是一个好主意。我建议您将 @PreAuthorize 注释添加到控制器/服务方法中。由于您有一个查询参数?projection=details,因此您可以为详细信息投影使用单独的控制器/服务方法。

    将以下内容添加到您的详细信息投影方法中:

    @RequestMapping("/url", params = {"projection"})
    @PreAuthorize("hasRole('LOGGED_IN') and principal.user.id == #id")
    

    【讨论】:

    • 我对这种方法有一个问题,即使用 Spring Data Rest 所有控制器和服务都是由框架生成的,因此我只能处理可以配置安全性的存储库。我也有自定义 URL,这个解决方案非常适合。除非我完全弄错了,否则您能否告诉我如何保护 Spring Data Rest 生成的 URL,例如我在帖子中提到的 /users/{id} 和 /users/{id}/userPosts 而无需在 Repository 中添加这些注释?
    • 我也怀疑是否可以将 @RequestMapping 添加到 Spring 数据 Rest 投影?
    【解决方案2】:

    为此用例添加自定义控制器似乎是合理的。

    还请考虑:

    • 使用 @Value 注释评估投影中的访问权限
    • 为相同的数据库数据添加另一个实体,但为只读操作设置了不同的字段,例如使用继承(小心缓存等) - 取决于您的数据存储类型
    • 修改模型以将 User 实体拆分为两个不同的实体(配置文件、帐户),因为它们似乎具有不同的访问权限,甚至可能具有不同的操作
    • 您还可以添加 ResourceProcessor&lt;UserSummaryProjection&gt; 以编程方式评估访问权限并将资源内容(投影)替换为 DTO

    使用@Value 注释在投影中评估访问权限的示例:

    @Projection(types = User.class, name = "summary")
    public interface UserSummaryProjection {
      @Value("#{@userSecurity.canReadEmail(target) ? target.email: null}")
      String getEmail();
    }
    

    【讨论】:

      猜你喜欢
      • 2015-05-01
      • 2017-07-27
      • 1970-01-01
      • 2018-04-18
      • 2016-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-26
      相关资源
      最近更新 更多