我正在寻找一种使用 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
错误
表:作用
表:报告
表:report_roles
在这种情况下,角色为 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/