首页 > 解决方案 > 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
    ...
  }  
}

注意事项

您对替代解决方案有什么建议吗?

标签: spring-bootspring-securityauthorization

解决方案


除了另一个答案之外,您还可以为您的产品定义具有自定义授权逻辑的自己的 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) {
    ...
}

推荐阅读