Доступ на основе владения Spring - PullRequest
0 голосов
/ 28 мая 2020

Пожалуйста, не помечайте это как дубликат, поскольку имеющиеся решения содержат проблемы безопасности и не охватывают все CRUD-случаи!

Я хочу защитить определенные объекты, сравнивая сохраненные userId объекта с SecurityContextHolder.getContext().authentication.

Я знаю, что мне нужно получить объект перед выполнением операций, поскольку это единственный способ получить userId.

Я хочу защитить такие методы контроллера, как этот:

@GetMapping("/deliveryAddresses/{id}")
    fun getDeliveryAddressById(@PathVariable(value = "id") deliveryAddressId : Long): 
        ResponseEntity<BasicDeliveryAddress> {
            return deliveryAddressService.findById(deliveryAddressId)?.let { ResponseEntity.ok(it) } 
                ?: ResponseEntity.notFound().build()
    }

Как лучше всего защитить этот объект? Я не хочу, чтобы в моем коде было несколько повторяющихся проверок владения. Также предложите, где добавить проверку (Контроллер, Сервис, ...?)

Это именно то, чего я хочу избежать (псевдокод):

fetchById(id) {
    val myObject = ...
    if(myObject.userId == authUser.userId) {
        ...
    }
}

Пожалуйста, предоставьте чистое решение этой проблемы.

ОБНОВЛЕНИЕ - ЧАСТЬ РЕШЕНИЯ

Я не знал, что могу напрямую получить объект внутри заголовка метода, передав только идентификатор.

@GetMapping("/something/{id}")
fun getSomethingByID(@PathVariable(value = "id") something: Something): ResponseEntity<BasicDeliveryAddress> { ... }

С этой дополнительной информацией и ответом (принятым), предоставленным @Ken Chan, вы сможете легко реализовать безопасность на основе владения!

1 Ответ

1 голос
/ 29 мая 2020

Используйте @PreAuthorize, который позволяет вам определить SpEL, который будет оцениваться как логическое, чтобы увидеть, разрешено ли выполнение метода.

У вас есть несколько вариантов:

(1 ) Используйте SpEL для ссылки на метод bean-компонента, выполняющий проверку:

@PreAuthorize("@authzService.isAllowToDo(#deliveryAddressId)")
public ResponseEntity<BasicDeliveryAddress> getDeliveryAddressById(Long deliveryAddressId {

}


@Service
public class AuthzService{

    public boolean isAllowToDo(Long deliveryAddressId){
        //Do the checking here....
    }
}

(2) Используйте встроенное выражение hasPermission:

@PreAuthorize("hasPermission(#deliveryAddressId, 'read')")
public ResponseEntity<BasicDeliveryAddress> getDeliveryAddressById(Long deliveryAddressId{

}

Для работы требуется настроить PermissionEvaluator. Та же идея, что и (1), но это встроенное решение.

(3) Если журнал оценки c прост и разрешена подпись метода, вы можете напрямую выразить его с помощью SpEL:

@PreAuthorize("#deliveryAddress.userId == authentication.userId")
public ResponseEntity<BasicDeliveryAddress> getDeliveryAddressById(BasicDeliveryAddress deliveryAddress){

}

authentication является одним из встроенных -in выражение для доступа к объекту аутентификации в SecurityContextHolder, и я предполагаю, что вы уже настроили его, чтобы включить userId.

...