JavaRush /Курси /Модуль 5. Spring /Користувацькі ролі та права доступу: анотація @Secured

Користувацькі ролі та права доступу: анотація @Secured

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

У світі веб-застосунків користувачі — це не просто абстрактні "люди". Кожному користувачу може бути присвоєна роль, яка визначає, які дії він може виконувати. Це важливий аспект безпеки, бо забезпечує чітке розмежування доступу до даних і функціоналу.

Уяви, що ти розробляєш банківський додаток: клієнт може бачити свої рахунки, перераховувати кошти, але не може, наприклад, генерувати банківські звіти. А от адміністратор може. Щоб керувати цим розподілом на рівні коду, використовують роль-орієнтовану систему доступу. У 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(); // Шифруємо паролі
    }
}
Паролі обов'язково мають бути зашифровані! Використовуємо 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. Тестуємо застосунок

Запускаємо застосунок і тестуємо:

  1. Відкрий Postman або просто браузер.
  2. Спробуй звернутися до /admin і /user.

Якщо ти залогінився як admin, то доступ до /admin буде відкритий, а /user — заборонений. Для user — навпаки.

6. Додаємо кілька ролей до одного методу

Якщо метод доступний для кількох ролей, їх можна вказати як масив:


@Secured({"ROLE_ADMIN", "ROLE_MANAGER"})
public String managerOrAdminMethod() {
    return "Привіт, Менеджер або Адміністратор!";
}

Spring Security перевірить, чи належить користувач хоча б одній із вказаних ролей.


Особливості й типові помилки

  1. Ролі з префіксом ROLE_. Spring Security очікує, що всі ролі починатимуться з ROLE_. Якщо ти цього не зробиш, отримаєш помилку! Наприклад, замість ROLE_ADMIN вказав просто ADMIN — це не спрацює.
  2. Помилка 403 Forbidden. Якщо бачиш цю помилку, перевір, що:
    • Увімкнено підтримку @Secured через @EnableGlobalMethodSecurity(securedEnabled = true).
    • Роль користувача вказана правильно (з урахуванням ROLE_).
  3. Не налаштовуй ролі в контролерах без обґрунтування. Безпеку краще обмежувати на рівні сервісів. Це допомагає мінімізувати дублювання логіки.

Практичне застосування

Використання ролей і прав доступу — базовий, але дуже потужний інструмент для керування доступом у застосунках. Його використовують практично всюди: від невеликих інтернет-магазинів до складних корпоративних систем. Тому розуміння роботи @Secured — це не просто корисно, це необхідно.

Для складніших випадків ми розглянемо анотації @PreAuthorize і @PostAuthorize у наступних лекціях — вони дозволяють налаштовувати гнучкіші правила доступу з використанням SpEL (Spring Expression Language).

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