【问题标题】:Secure a Spring Webflux controller considering dynamic parameters with Spring Security annotations使用 Spring Security 注释保护考虑动态参数的 Spring Webflux 控制器
【发布时间】:2020-01-20 17:39:44
【问题描述】:

我有一个带有一些控制器的应用程序,这些控制器需要根据请求的资源 ID 进行访问控制,检查 Spring Security 用户身份验证角色。目前我已经创建了一个函数来检查这个条件是否可以返回Mono<True>(以便我可以对其进行平面映射)或一个空的 Mono(并且还设置一个 403 状态代码),否则:

@RestController
@RequestMapping("/api/v1/clients/{clientId}/departments/{departmentId}/users")
class UserRestController(private val userService: UserService) {

    @GetMapping
    fun getAll(principal: Principal, response: ServerHttpResponse,
               @PathVariable clientId: String, @PathVariable departmentId: String): Flux<Users> {
        return checkDepartmentViewPermissions(principal, response, clientId, departmentId)
                .flatMap {
                    userService.getAll(clientId, departmentId)
                }
    }

    ...
}

fun checkDepartmentViewPermissions(principal: Principal, response: ServerHttpResponse, 
         clientId: String, departmentId: String): Mono<Boolean> {
    val authentication = principal as MyAuthentication
    authentication.authorities.contains(SimpleGrantedAuthority("${clientId}:${departmentId}")).toMono()
            .filter {
                it == true
            }.switchIfEmpty {
                response.statusCode = HttpStatus.FORBIDDEN
                Mono.empty()
            }
}


如上所示,请求的格式为/api/v1/clients/{clientId}/departments/{departmentId}/users,其中clientIddepartmentId 是动态路径变量。

checkDepartmentViewPermission 方法访问Authentication 角色,其中用户将拥有一个列表,例如 (client1:department1, client1:department2, client2:department1)。因此,URL /api/v1/clients/client1/departments/department1/users 可以很好地满足这些权限。

虽然我有什么工作,但如果可能的话,我想使用一种更具声明性的方式来处理这个问题,理想情况下基于 Spring Security 注释并考虑到我需要访问 PathVariable 参数,例如(I'我在弥补):

@RestController
@RequestMapping("/api/v1/clients/{clientId}/departments/{departmentId}/users")
class UserRestController(private val userService: UserService) {

    @PreAuthorize("#{principal.roles.contains(clientId:departmentId)}")
    @GetMapping
    fun getAll(principal: Principal, response: ServerHttpResponse,
               @PathVariable clientId: String, @PathVariable departmentId: String): Flux<Users> {
        return userService.getAll(clientId, departmentId)
    }

    ...
}

Spring Security 是否支持这样做的方法? 如果没有,您能提出任何实现它的想法吗?

【问题讨论】:

  • 你可以在 Spring EL 中访问方法输入参数,方法是在其名称前加上 # 前缀,如 #departmentId 所以试试 #{principal.roles.contains(#clientId, #departmentId)} 你可以编写自己的 spring bean 并在 Spring EL @987654335 中调用它@

标签: spring spring-security spring-webflux


【解决方案1】:

首先,感谢 Thomas 为我指明了正确的方向,我还没有意识到 we can invoke a Spring bean from the security web expressions。这样,就不再需要注入主体了,因为 Authentication 对象将被传递给 bean。

控制器

   @PreAuthorize("@permissionChecker.hasDepartmentViewPermissions(authentication, #clientId, #departmentId)")
    @GetMapping
    fun getAll(@PathVariable clientId: String, @PathVariable departmentId: String): Flux<Users> {
        return userService.getAll(clientId, departmentId)
    }

PermissionChecker bean:

class PermissionChecker {

    fun hasDepartmentViewPermissions(authentication: Authentication, clientId: String, projectId: String): Boolean {
        ...
    }

【讨论】:

  • 很高兴我能帮上忙。
猜你喜欢
  • 1970-01-01
  • 2014-03-09
  • 2014-11-03
  • 2020-04-02
  • 2012-10-05
  • 2011-06-28
  • 1970-01-01
  • 1970-01-01
  • 2016-06-03
相关资源
最近更新 更多