JavaRush /Курси /Модуль 5. Spring /Конфігурація безпеки через анотації

Конфігурація безпеки через анотації

Модуль 5. Spring
Рівень 17 , Лекція 2
Відкрита

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), а вже ролі мають доступ до певних ресурсів. Це дозволяє ефективно керувати правами доступу, централізовано задаючи правила.


Практика: Налаштування безпеки з анотаціями

Давайте створимо сервіс, де користувачі зможуть:

  1. Переглянути список своїх задач (доступно тільки користувачам з роллю ROLE_USER).
  2. Видалити задачу (доступно тільки адміністраторам).

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);
    }
}

Тепер ми налаштували авторизацію і через ролі, і через вирази.


Типові помилки

  1. Забули активувати анотації: якщо не включити @EnableGlobalMethodSecurity, жодна анотація не працюватиме.
  2. Відсутність ролей у користувача: якщо в користувача не призначені ролі, всі захищені методи будуть для нього недоступні.
  3. Змішування різних анотацій: якщо ти використовуєш і @PreAuthorize, і @Secured, не забудь увімкнути підтримку обох параметрів.

Тепер ти знаєш, як конфігурувати безпеку за допомогою анотацій. Це потужний інструмент, який спрощує керування доступом у застосунках.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ