spring-boot - Spring Security:使用域逻辑进行授权
问题描述
先决条件
我正在使用 Spring Security 通过 firebase 对我的用户进行身份验证。在身份验证期间,我还从 JWT 令牌中提取用户角色并将其转换为SimpleGrantedAuthorities
.
在大多数情况下,我可以使用@PreAuthorize("hasRole('ROLE_ADMIN')")
将授权应用于端点。但现在我有一个更复杂的授权场景。
我有一个Service
获取 a 的 a Product
,但只有购买了该产品的用户才被允许接收它。
fun fetchProduct(val id: Int, userId: String) {
val product = productRepository.findById(id)
// only users that purchased the product are allowed to fetch it!
if (!product.isAccessibleAtNoCharge(userId) && !purchaseCheck.hasUserPurchased(userId, product.id)) {
throw ForbiddenException("User has not purchased product")
}
return product
}
我想要达到的目标
我的要求是,具有该角色的用户ROLE_ADMIN
可以绕过该检查,以便他们可以访问产品而无需之前购买它们。
我试过的
到目前为止,我唯一的想法是SecurityContext
像这样检索角色:
fun fetchProduct(val id: Int, userId: String) {
val product = productRepository.findById(id)
val isAdmin = SecurityContextHolder.getContext().authentication.authorities.any { it.authority == "ROLE_ADMIN" }
if(isAdmin) {
return product
} else {
// check if purchased
...
}
}
注意事项
- 我怀疑这个解决方案是否可以很好地测试,因为静态方法调用
- 感觉方案没有抽象(业务逻辑和授权逻辑混用)
- 通常授权似乎是在控制器中完成的,这在这种情况下是不可能的?
您对替代解决方案有什么建议吗?
解决方案
除了另一个答案之外,您还可以为您的产品定义具有自定义授权逻辑的自己的 bean,并在SPeL中调用它。
@Component
public class ProductPermissionEvaluator {
public boolean canFetchProduct(Long productId, Long userId) {
// perform your logic
}
}
@PreAuthorize("hasRole('ADMIN') || @productPermissionEvaluator.canFetchProduct(#id, #userId)")
fun fetchProduct(val id: Int, userId: String) {
...
}
推荐阅读
- ios - JSONSerialize 并将 JSON 发布到 Swift 中的服务器
- angular - *ngIf = "true" 应用于表单时无法访问表单数据
- mysql - 创建一个虚拟列,汇总不同表中列的值
- flutter - 在运行时构建的通用颤振应用程序中的状态管理
- html - 有没有办法在 wordpress 中查找和编辑特定的 html 片段?
- outlook - 访问令牌验证失败 - MS Graph API 版本 2
- php - 本地 Apache 服务器 - 尝试通过 bash 脚本安装 PHP5.6 后拒绝连接
- ios - Xcode 中的 Firebase 身份验证和实时数据库:如何仅显示与一个用户相关的数据而不是全部?
- python - 检查数据框是否具有完整数据网格的有效方法
- mysql - SQL将空值的总和转换为0