У меня есть приложение с некоторыми контроллерами, которые требуют контроля доступа на основе запрошенных идентификаторов ресурсов, сравнивая их с ролями аутентификации пользователя Spring Security.На данный момент я создал функцию, которая проверяет это условие, возвращая Mono<True>
, если оно в порядке (чтобы я мог отобразить его), или пустое моно (а также устанавливая код состояния 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
, где clientId
и departmentId
- переменные динамического пути.
Метод checkDepartmentViewPermission
обеспечивает доступ к ролям Authentication
, где пользователи будут иметьсписок, такой как (client1:department1, client1:department2, client2:department1
).Таким образом, URL /api/v1/clients/client1/departments/department1/users
будет нормально работать для этих разрешений.
Хотя то, что у меня работает, я хотел бы использовать более декларативный способ решения этой проблемы, если это возможно, в идеале что-то, основанное на Spring Securityаннотации и с учетом того, что мне нужно получить доступ к параметрам PathVariable, что-то вроде (я делаю это):
@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 способ сделать это?Если нет, не могли бы вы предложить какие-либо идеи для его достижения?