java - Spring Boot/JPA - 数据行级授权

标签 java spring-boot hibernate jpa spring-security

我正在寻找一种使用 Spring Boot 和 JPA 根据角色和数据内容(表行)授权访问的方法

用例如下:

Given a User with a Role 'ROLE_AAA'
When user fetches data from table 'REPORT'
Then only reports with specific 'REPORT_ROLE' association will be returned

错误

表:作用

<表类="s-表"> <头> 身份证 角色 <正文> 1 ROLE_AAA 2 ROLE_BBB

表:报告

<表类="s-表"> <头> 身份证 内容 <正文> 1 ... 2 ... 3 ... 4 ... 5 ...

表:report_roles

<表类="s-表"> <头> REPORT_ID ROLE_ID <正文> 1 1 2 1 3 2 4 2 5 1

在这种情况下,角色为 ROLE_AAA 的用户将仅获得 ID 为 1,2 和 5 的报告。

SELECT re.*
FROM report re
JOIN report_role rr
ON re.id = rr.report_id
JOIN role ro
ON ro.id = rr.role_id
WHERE ro.name = 'ROLE_AAA'

我可以轻松地编写查询 (@org.springframework.data.jpa.repository.Query) 加入我想从中获取数据的表,以及关联角色表,但我觉得我缺少 JPA 或 Spring Security开箱即用的功能。

我们将不胜感激任何设计/实现建议。

更新

由于返回将被分页 ( retuning Page<Object> from JPARepository ),我相信 PostFiltering 不是这里的一个选项。

最佳答案

这是我写的一篇关于使用 @Pre/Post annotations with a custom PermissionEvaluator 的旧文章.这似乎是您最好的选择,并且允许您纯粹使用注释而不是自定义查询。当然,只有在您的查询返回的报告不多的情况下(没有 ro.name = 'ROLE_AAA' 过滤器)它才有效。

但是,在您的情况下,您并没有真正尝试使用 hasPermission(filterObject, 'xyz') 语法,因为您的用例是基于角色的,这意味着权限是角色 并且已经在身份验证对象(例如 authorities)和数据库(例如 report_roles)中。通过用户角色和报告角色之间的 M:N 关系,您可以实现一个助手来为您进行检查,如下所示:

@RestController
public class ReportsController {
    @GetMapping("/reports")
    @PostFilter("@reportExpressions.hasAnyRole(filterObject, authentication)")
    public List<Report> getReports() {
        return new ArrayList<>(List.of(
            new Report("Report #1", Set.of("ROLE_AAA", "ROLE_BBB")),
            new Report("Report #2", Set.of("ROLE_AAA", "ROLE_CCC"))
        ));
    }

    @Component("reportExpressions")
    public static class ReportExpressions {
        public boolean hasAnyRole(Report report, Authentication authentication) {
            Set<String> authorities = AuthorityUtils.authorityListToSet(
                authentication.getAuthorities());
            return report.getRoles().stream().anyMatch(authorities::contains);
        }
    }

    public static class Report {
        private final String name;
        private final Set<String> roles;

        public Report(String name, Set<String> roles) {
            this.name = name;
            this.roles = roles;
        }

        public String getName() {
            return name;
        }

        public Set<String> getRoles() {
            return roles;
        }
    }
}

如果当前用户拥有 ROLE_AAA,他们将看到两个报告等。我的示例使用 Controller ,但您可以将相同的注释应用于 JPA 存储库。

关于java - Spring Boot/JPA - 数据行级授权,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69708298/

相关文章:

spring-security - 撤销 JWT Oauth2 刷新 token

java - 如何使用 Java 中的 ta-lib 修复 RSI 计算输出中的零?

hibernate - 刷新页面时 grails 中奇怪的 GORM 行为 (F5)

eclipse - hibernate "generated by hibernate tools"

java - @EJB 注释不适用于 EJB 应用程序中的初始化 bean

java - 如何使用spring-data保存实体的子实体

java - 使用具有安全性的 spring mvc 时,为匿名用户存储一些数据的最佳方法是什么?

java - 如何使用Java Config手动添加Spring CacheInterceptor?

java - 如何使用 JPA Hibernate 从 PostgreSQL 检索时间戳值 "-infinity"

java - 如何在 Spring + JPA + Hibernate 设置中获得 "start of transaction"时间戳?