У світі веб-застосунків користувачі — це не просто абстрактні "люди". Кожному користувачу може бути присвоєна роль, яка визначає, які дії він може виконувати. Це важливий аспект безпеки, бо забезпечує чітке розмежування доступу до даних і функціоналу.
Уяви, що ти розробляєш банківський додаток: клієнт може бачити свої рахунки, перераховувати кошти, але не може, наприклад, генерувати банківські звіти. А от адміністратор може. Щоб керувати цим розподілом на рівні коду, використовують роль-орієнтовану систему доступу. У Spring Security це робиться за допомогою анотації @Secured.
Анотація @Secured дозволяє налаштувати доступ до методів або ресурсів на підставі ролей користувачів. Її можна використовувати для обмеження доступу на рівні сервісів, контролерів або навіть окремих бізнес-методів.
Офіційна документація: Spring Security: @Secured
Налаштування ролі та безпеки з використанням @Secured
Давай розберемося з цим крок за кроком.
1. Налаштування проєкту
Створимо просте Spring Boot-застосування, де будемо працювати з користувачами і ролями. Переконайся, що в тебе підключений Spring Security.
Додаємо залежності в pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
Конфігурація безпеки
Щоб застосувати @Secured, потрібно ввімкнути підтримку безпеки на рівні методів.
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true) // Увімкнемо підтримку @Secured
public class SecurityConfig {
// У цій лекції використовується вбудована конфігурація користувача (InMemoryUserDetailsManager),
// Більш складні приклади з базою даних розберемо пізніше.
}
2. Визначаємо ролі й користувачів
Для тестування створимо ролі й користувачів в пам'яті (InMemoryUserDetailsManager).
Задаємо користувачів і ролі:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration
public class UserConfig {
@Bean
public InMemoryUserDetailsManager userDetailsManager() {
UserDetails admin = User.builder()
.username("admin")
.password(passwordEncoder().encode("admin123"))
.roles("ADMIN") // Роль адміністратора
.build();
UserDetails user = User.builder()
.username("user")
.password(passwordEncoder().encode("user123"))
.roles("USER") // Роль користувача
.build();
return new InMemoryUserDetailsManager(admin, user);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(); // Шифруємо паролі
}
}
3. Використання @Secured у сервісах
Створимо простий сервіс і обмежимо доступ до його методів на основі ролей.
Реалізуємо сервіс:
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Service;
@Service
public class MyService {
@Secured("ROLE_ADMIN") // Доступ тільки для адміністраторів
public String adminMethod() {
return "Привіт, Адміністратор!";
}
@Secured("ROLE_USER") // Доступ тільки для користувачів
public String userMethod() {
return "Привіт, Користувач!";
}
}
Зауваж, що ролі мають бути вказані з префіксом ROLE_. Наприклад, ROLE_ADMIN. Це стандарт Spring Security.
4. Створюємо контролер для тестування
Тепер створимо REST-контролер, який використовуватиме наш сервіс.
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyController {
private final MyService myService;
public MyController(MyService myService) {
this.myService = myService;
}
@GetMapping("/admin")
public String adminEndpoint() {
return myService.adminMethod();
}
@GetMapping("/user")
public String userEndpoint() {
return myService.userMethod();
}
}
5. Тестуємо застосунок
Запускаємо застосунок і тестуємо:
- Відкрий Postman або просто браузер.
- Спробуй звернутися до
/adminі/user.
Якщо ти залогінився як admin, то доступ до /admin буде відкритий, а /user — заборонений. Для user — навпаки.
6. Додаємо кілька ролей до одного методу
Якщо метод доступний для кількох ролей, їх можна вказати як масив:
@Secured({"ROLE_ADMIN", "ROLE_MANAGER"})
public String managerOrAdminMethod() {
return "Привіт, Менеджер або Адміністратор!";
}
Spring Security перевірить, чи належить користувач хоча б одній із вказаних ролей.
Особливості й типові помилки
- Ролі з префіксом
ROLE_. Spring Security очікує, що всі ролі починатимуться зROLE_. Якщо ти цього не зробиш, отримаєш помилку! Наприклад, замістьROLE_ADMINвказав простоADMIN— це не спрацює. - Помилка
403 Forbidden. Якщо бачиш цю помилку, перевір, що:- Увімкнено підтримку
@Securedчерез@EnableGlobalMethodSecurity(securedEnabled = true). - Роль користувача вказана правильно (з урахуванням
ROLE_).
- Увімкнено підтримку
- Не налаштовуй ролі в контролерах без обґрунтування. Безпеку краще обмежувати на рівні сервісів. Це допомагає мінімізувати дублювання логіки.
Практичне застосування
Використання ролей і прав доступу — базовий, але дуже потужний інструмент для керування доступом у застосунках. Його використовують практично всюди: від невеликих інтернет-магазинів до складних корпоративних систем. Тому розуміння роботи @Secured — це не просто корисно, це необхідно.
Для складніших випадків ми розглянемо анотації @PreAuthorize і @PostAuthorize у наступних лекціях — вони дозволяють налаштовувати гнучкіші правила доступу з використанням SpEL (Spring Expression Language).
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ