Spring Security надає потужний механізм для конфігурації безпеки через анотації. Це робить наш код не лише компактнішим, але й читабельнішим. Анотації дозволяють розмежовувати доступ до ресурсів і методів прямо там, де вони використовуються.
У цій лекції ми вивчимо чотири основні анотації:
@Secured@RolesAllowed@PreAuthorize@PostAuthorize
Анотація @Secured
Анотація @Secured задає ролі, яким дозволений доступ до методу або ресурсу. Вона проста й зручна, якщо потрібен швидкий спосіб обмежити доступ на основі ролей.
@Secured перевіряє, чи має користувач певну роль (наприклад, ROLE_USER), щоб він міг викликати цей метод.
Приклад:
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Service;
@Service
public class MyService {
@Secured("ROLE_ADMIN")
public void adminOnlyMethod() {
System.out.println("Цей метод доступний тільки для адміністраторів!");
}
@Secured({"ROLE_USER", "ROLE_ADMIN"})
public void userOrAdminMethod() {
System.out.println("Цей метод доступний для користувачів та адміністраторів.");
}
}
@EnableGlobalMethodSecurity з параметром
securedEnabled = true.
Як активувати? Додай наступну налаштування в клас конфігурації безпеки:
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true) // Включаємо підтримку @Secured
public class SecurityConfig {
// Тут можна додавати додаткові конфігурації
}
Анотація @RolesAllowed
@RolesAllowed — це анотація зі стандарту JSR-250, яка дуже схожа на @Secured. Вона також перевіряє ролі користувача, але є більш "офіційною" в контексті стандартів Java.
Приклад використання:
import javax.annotation.security.RolesAllowed;
import org.springframework.stereotype.Service;
@Service
public class AnotherService {
@RolesAllowed("ROLE_MANAGER")
public String managerOnly() {
return "Доступно тільки для менеджерів!";
}
}
Увімкнення @RolesAllowed. Щоб ця анотація працювала, її треба активувати в конфігурації безпеки:
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
@Configuration
@EnableGlobalMethodSecurity(jsr250Enabled = true) // Включаємо підтримку @RolesAllowed
public class SecurityConfig {
}
@Secured і
@RolesAllowed одночасно, потрібно активувати обидва параметри (
securedEnabled = true і
jsr250Enabled = true).
Анотація @PreAuthorize
Це вже потужніша анотація, яка дозволяє використовувати SpEL (Spring Expression Language) для визначення умов доступу. Можна перевіряти не лише ролі, а й значення атрибутів об'єкта, який метод отримує на вхід.
Наприклад, можна написати умову на кшталт "доступ дозволений тільки користувачам, у яких email закінчується на @example.com".
Приклад:
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
@Service
public class EmailService {
@PreAuthorize("hasRole('ROLE_USER')")
public void generalAccess() {
System.out.println("Цей метод доступний тільки для користувачів з роллю ROLE_USER.");
}
@PreAuthorize("#email.endsWith('@example.com')")
public void sendEmail(String email) {
System.out.println("Відправка email на адресу: " + email);
}
}
hasRole, а в другому використовується вираз, який залежить від параметра методу.
Увімкнення @PreAuthorize
Щоб активувати підтримку цієї анотації, додай у конфігурацію:
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true) // Включаємо підтримку @PreAuthorize і @PostAuthorize
public class SecurityConfig {
}
Анотація @PostAuthorize
Чим вона відрізняється від @PreAuthorize? Якщо @PreAuthorize перевіряє доступ до виклику методу, то @PostAuthorize робить це після виконання методу. Це корисно, коли хочеш перевірити результат виконання методу перед тим, як повернути його викликавчій стороні.
Приклад:
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.stereotype.Service;
@Service
public class DocumentService {
@PostAuthorize("returnObject.owner == authentication.name")
public Document getDocumentById(Long id) {
Document document = findDocumentById(id); // Логіка пошуку документа
return document; // Перевірка, що поточний користувач є власником документа
}
}
У цьому прикладі дозвол повернути документ перевіряється вже після того, як метод його знайшов. Якщо поточний користувач не є власником документа, Spring Security кине виключення.
Role-based Access Control (RBAC)
Тепер, коли ми вивчили анотації, давайте обговоримо, як це все пов'язано з концепцією керування доступом на основі ролей.
У системі RBAC користувачі отримують певні ролі (наприклад, ROLE_USER, ROLE_ADMIN), а вже ролі мають доступ до певних ресурсів. Це дозволяє ефективно керувати правами доступу, централізовано задаючи правила.
Практика: Налаштування безпеки з анотаціями
Давайте створимо сервіс, де користувачі зможуть:
- Переглянути список своїх задач (доступно тільки користувачам з роллю
ROLE_USER). - Видалити задачу (доступно тільки адміністраторам).
public class Task {
private Long id;
private String name;
private String owner;
// Getters і Setters
}
Сервіс:
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class TaskService {
private List<Task> tasks = new ArrayList<>();
public TaskService() {
// Додамо кілька задач для прикладу
tasks.add(new Task(1L, "Купити молоко", "user1"));
tasks.add(new Task(2L, "Зробити домашку", "user2"));
}
@PreAuthorize("hasRole('ROLE_USER')")
public List<Task> getUserTasks(String owner) {
// Логіка фільтрації задач за власником
return tasks.stream()
.filter(task -> task.getOwner().equals(owner))
.toList();
}
@Secured("ROLE_ADMIN")
public void deleteTask(Long id) {
// Логіка видалення задачі
tasks.removeIf(task -> task.getId().equals(id));
}
}
Контролер:
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/tasks")
public class TaskController {
private final TaskService taskService;
public TaskController(TaskService taskService) {
this.taskService = taskService;
}
@GetMapping
public List<Task> getTasks(@RequestParam String owner) {
return taskService.getUserTasks(owner);
}
@DeleteMapping("/{id}")
public void deleteTask(@PathVariable Long id) {
taskService.deleteTask(id);
}
}
Тепер ми налаштували авторизацію і через ролі, і через вирази.
Типові помилки
- Забули активувати анотації: якщо не включити
@EnableGlobalMethodSecurity, жодна анотація не працюватиме. - Відсутність ролей у користувача: якщо в користувача не призначені ролі, всі захищені методи будуть для нього недоступні.
- Змішування різних анотацій: якщо ти використовуєш і
@PreAuthorize, і@Secured, не забудь увімкнути підтримку обох параметрів.
Тепер ти знаєш, як конфігурувати безпеку за допомогою анотацій. Це потужний інструмент, який спрощує керування доступом у застосунках.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ