Как разрешить пользователю доступ только к своим данным в Spring Boot / Spring Security?

У меня есть api отдыха вроде этого:

/users/{user_id}
/users/{user_id}/orders
/users/{user_id}/orders/{order_id}

Как я должен их обезопасить? каждый пользователь должен видеть только свои данные, но администратор может видеть их все.

Как и что я должен реализовать в Spring Security, чтобы пользователь с идентификатором == 1 не мог видеть данные пользователя с идентификатором == 2 и наоборот, ожидать пользователей с ролью администратора, которые могут видеть все?

Должен ли я проверять, прежде чем каждый метод User Id в сеансе равен параметру user_id, переданному в api? Есть ли способ лучше?

p.s: Я использую JWT по spring security.

12
0
11 497
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

В любом аннотированном компоненте @Controller, @RestController вы можете использовать Principal непосредственно в качестве аргумента метода.

    @RequestMapping("/users/{user_id}")
    public String getUserInfo(@PathVariable("user_id") Long userId, Principal principal){
        // test if userId is current principal or principal is an ADMIN
        ....
    }

Если вам не нужны проверки безопасности в ваших Controller, вы можете использовать выражения Spring EL. Вероятно, вы уже используете некоторые встроенные выражения, такие как hasRole([role]).

И вы можете писать свои собственные выражения.

  1. Создайте bean
    @Component("userSecurity")
    public class UserSecurity {
         public boolean hasUserId(Authentication authentication, Long userId) {
            // do your check(s) here
        }
    }
  1. Используйте свое выражение
    http
     .authorizeRequests()
     .antMatchers("/user/{userId}/**")
          .access("@userSecurity.hasUserId(authentication,#userId)")
        ...

Приятно то, что вы также можете комбинировать такие выражения, как:

    hasRole('admin') or @userSecurity.hasUserId(authentication,#userId)

Могу ли я сделать это с помощью АОП?

GLinBoy 07.08.2018 05:45

Если у вас возникли проблемы с пользовательским выражением, добавьте «@Component ("userSecurity")» над строкой «public class UserSecurity {».

Krishna Chikkala 13.04.2020 20:34

Но «В любом @Controller, аннотированном компоненте @RestController вы можете использовать Principal непосредственно в качестве аргумента метода». не работает. Директор просто null

ACV 04.09.2020 14:33

@ACV да .... Должен быть доступен Принципал ref: главный-в-отдыхающем контроллере

Dirk Deyne 04.09.2020 15:22

Спасибо @DirkDeyne, что вы создали пример специально для демонстрации. Хороший. Так как же запросить эту конечную точку, чтобы Принципал не был нулевым? Это заголовок запроса или что-то еще? Как Spring заполняет этот объект?

ACV 04.09.2020 17:18

@ACV вот хороший обзор Руководство spring.io: Spring-Security-Architecture, вы должны посмотреть на Web Security часть

Dirk Deyne 04.09.2020 18:02

Вы также можете использовать @PreAuthorize в интерфейсе службы. Если у вас есть собственный объект userdetails, вы можете легко это сделать. В одном из своих проектов я сделал это так:

@PreAuthorize(value = "hasAuthority('ADMIN')"
        + "or authentication.principal.equals(#post.member) ")
void deletePost(Post post);

Кстати, это в служебном интерфейсе. Вы должны убедиться, что добавили правильные аннотации, чтобы получить предварительную авторизацию для работы.

Сначала вы должны выбрать свою стратегию безопасности, То, что вам нужно, называется "Фильтрация строк", одна из концепций авторизации концепции 3A (аутентификация, авторизация, аудит).

Если вы хотите реализовать комплексное решение, обратите внимание на:

https://docs.spring.io/spring-security/site/docs/3.0.x/reference/domain-acls.html

Spring ACL полностью охватывает такие понятия, как «Фильтрация строк», «Белый-черный список», «Авторизация по ролевой базе», «Наследование ACL», «Ролевой избиратель» и т. д.

В противном случае вам следует сохранить владельца для каждого бизнес-кейса, который вы хотите защитить, и отфильтровать их на своем уровне обслуживания.

Мы можем создать аннотацию наподобие @IsUser и использовать ее с методом контроллера.

Пример :

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@PreAuthorize(value = "hasRole('ROLE_USER')" + "and authentication.principal.equals(#userId) ")
public @interface IsUser { }

Другие вопросы по теме