У меня есть 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.
В любом аннотированном компоненте @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]).
И вы можете писать свои собственные выражения.
bean @Component("userSecurity")
public class UserSecurity {
public boolean hasUserId(Authentication authentication, Long userId) {
// do your check(s) here
}
}
http
.authorizeRequests()
.antMatchers("/user/{userId}/**")
.access("@userSecurity.hasUserId(authentication,#userId)")
...
Приятно то, что вы также можете комбинировать такие выражения, как:
hasRole('admin') or @userSecurity.hasUserId(authentication,#userId)
Если у вас возникли проблемы с пользовательским выражением, добавьте «@Component ("userSecurity")» над строкой «public class UserSecurity {».
Но «В любом @Controller, аннотированном компоненте @RestController вы можете использовать Principal непосредственно в качестве аргумента метода». не работает. Директор просто null
@ACV да .... Должен быть доступен Принципал ref: главный-в-отдыхающем контроллере
Спасибо @DirkDeyne, что вы создали пример специально для демонстрации. Хороший. Так как же запросить эту конечную точку, чтобы Принципал не был нулевым? Это заголовок запроса или что-то еще? Как Spring заполняет этот объект?
@ACV вот хороший обзор Руководство spring.io: Spring-Security-Architecture, вы должны посмотреть на Web Security часть
Вы также можете использовать @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 { }
Могу ли я сделать это с помощью АОП?