Сьогодні переходимо до практики — створимо базовий веб-застосунок з налаштуванням Spring Security для захисту маршрутів і реалізації аутентифікації користувачів. Готуйтеся до бою, друзі!
Від побудови застосунку до додавання безпеки
Мета та структура задачі
Перш ніж писати код, давайте уявимо, що ми створюємо не просто застосунок, а цифровий ресторан. Потрібно зрозуміти, хто прийшов у гості (аутентифікація) і куди їх можна пустити (авторизація). У звичайному ресторані є фейс-контроль і VIP-зони, а в нашому застосунку буде Spring Security.
Ось наш план дій:
- Створимо мінімальний Spring Boot застосунок — наш "ресторан"
- Додамо базовий захист за допомогою Spring Security — встановимо "двері й замки"
- Налаштуємо систему перевірки відвідувачів — хто ви і чи можна вам довіряти?
- Визначимо правила доступу до різних зон — хто куди може ходити
- Перевіримо нашу систему безпеки через браузер або Postman — влаштуємо тестовий "візит"
Готові побудувати найбезпечніший цифровий ресторан? Поїхали!
Крок 1: Створюємо мінімалістичний Spring Boot застосунок
Спочатку створимо новий проект Spring Boot. Вибираємо залежності:
- Spring Web — щоб наш застосунок міг обробляти HTTP-запити.
- Spring Security — власне, для налаштування безпеки.
Не забудьте додати Gradle або Maven в ваш проєкт. Наприклад, для Maven ваш pom.xml виглядатиме так:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
Тепер додамо простий контролер.
@RestController
public class GreetingController {
@GetMapping("/public")
public String publicEndpoint() {
return "Цей ендпоінт доступний усім!";
}
@GetMapping("/secure")
public String secureEndpoint() {
return "Ви зайшли у захищену зону!";
}
}
Запустіть застосунок і спробуйте відкрити маршрути /public і /secure. Зверніть увагу, що Spring Security уже захищає весь ваш API. Спробуйте дістатися до /secure, і ви побачите вікно логіну в браузері. Це базовий захист, який надає Spring Security "з коробки".
Крок 2: Налаштовуємо базову конфігурацію
Тепер створимо кастомну конфігурацію безпеки. Нам потрібно зробити так, щоб:
/publicзалишався відкритим для всіх./secureбув захищений і доступний тільки аутентифікованим користувачам.
Створимо конфігураційний клас.
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/public").permitAll() // Доступ відкритий для всіх
.anyRequest().authenticated() // Усі інші запити потребують аутентифікації
.and()
.formLogin() // Вмикаємо стандартну форму логіну
.and()
.httpBasic(); // Вмикаємо HTTP Basic авторизацію
}
}
Запустіть застосунок заново. Тепер /public відкривається без проблем, а доступ до /secure вимагає введення імені користувача та пароля через стандартну форму логіну.
Крок 3: Налаштування користувачів
За замовчуванням Spring Security використовує передвстановленого користувача з ім'ям user і випадковим паролем, який відображається в логах застосунку при запуску. Якщо вам набридло бігати очима по логам у пошуках пароля, давайте додамо власних користувачів в application.properties.
spring.security.user.name=admin
spring.security.user.password=admin123
Тепер користувач admin зможе аутентифікуватися з паролем admin123.
Але що робити, якщо потрібно додати різні ролі (наприклад, адміністраторів і звичайних користувачів)? Трохи піднастроїмо систему.
Крок 4: Додаємо авторизацію на основі ролей
Ми додамо дві ролі: ROLE_ADMIN і ROLE_USER. Для цього спочатку оновимо нашу конфігурацію безпеки:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/public").permitAll()
.antMatchers("/secure").hasRole("ADMIN") // Доступ до /secure тільки для адмінів
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.httpBasic();
}
Тепер створимо користувачів з різними ролями. Для цього перевизначимо метод configure у нашому класі SecurityConfig:
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin").password(passwordEncoder().encode("admin123")).roles("ADMIN") // Адмін
.and()
.withUser("user").password(passwordEncoder().encode("user123")).roles("USER"); // Звичайний користувач
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
Тепер у нас два користувачі:
adminз паролемadmin123і роллюROLE_ADMIN.userз паролемuser123і роллюROLE_USER.
І тільки адміністратор (admin) зможе отримати доступ до /secure.
Крок 5: Тестуємо безпеку
Запустіть застосунок і протестуйте його:
- Відкрийте
/public— доступ відкритий для всіх. - Відкрийте
/secure— система запросить логін і пароль.- Введіть
user/user123— отримаєте відмову в доступі. - Введіть
admin/admin123— отримаєте доступ.
- Введіть
Для тестування також можна використовувати Postman. Наприклад, запит до /secure можна відправити з Basic Auth, вказавши ім'я користувача і пароль.
Крок 6: Перевіряємо файл application.properties
Ось що можна додати в application.properties для зручності:
# Логування для налагодження
logging.level.org.springframework.security=DEBUG
Так ви зможете бачити більше інформації про те, як Spring Security обробляє ваші запити.
Часті помилки
- Помилка: доступ до захищених маршрутів надається будь-якому користувачу. Зазвичай це трапляється через неправильно налаштовані правила у
authorizeRequests. Перевірте порядок викликівantMatchers— вони обробляються зверху вниз. IllegalArgumentException: There is no PasswordEncoder mapped for ID "null". Це трапляється, якщо ви забули налаштуватиPasswordEncoder. Не забудьте додати бинBCryptPasswordEncoderу ваш код, щоб шифрувати паролі.
Наступний крок — впровадження збереження користувачів і ролей у базі даних, що ми розглянемо в наступних лекціях. Куди ж без інтеграції з реальною базою, правда?
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ