Кожен додаток, чи то гігантський онлайн-магазин, чи невеликий сервіс нотаток, має певні ресурси, які потребують захисту: це можуть бути дані користувачів, конфіденційна інформація або операції, що змінюють стан системи. І наше завдання як розробників — зробити ці ресурси доступними тільки для тих, хто має право на доступ.
Без адекватного рівня захисту будь-хто з базовим ПО (так, ми дивимось у бік Postman) зможе отримати доступ до API, а ми цього точно допускати не хочемо.
OAuth2 дає відмінний інструмент для керування доступом: токени. І сьогодні розберемося, як налаштувати ваш Spring Boot проєкт, щоб забезпечити строгий захист на рівні ресурсів.
Компоненти захисту ресурсів
Перш ніж занурюватись у практику, давайте коротко визначимо ключові компоненти, які потрібні для захисту ресурсів з OAuth2:
- Ресурсний сервер (Resource Server):
- Компонент, який обслуговує захищені дані та перевіряє токени перед наданням доступу. Тут зазвичай розгортаються ваші REST API.
- Токен доступу (Access Token):
- Спеціальний токен, з яким клієнт може стукати у двері до ресурсного сервера. Токен несе в собі інформацію, наприклад, які дії дозволені і для якого користувача.
- Ролі та права доступу:
- Керування доступом через ролі (наприклад,
ROLE_USER,ROLE_ADMIN) і області (scopes), які визначають функціональні можливості користувача.
- Керування доступом через ролі (наприклад,
- Spring Security:
- Фреймворк, який дозволяє організувати перевірку прав доступу до ресурсів, перевірку токенів і налаштування політик безпеки.
Реалізація захисту ресурсів у Spring Boot
Переходимо до практики. Налаштовуватимемо Spring Boot додаток у ролі ресурсного сервера, використовуючи OAuth2 і JWT.
Підготовка проєкту
Переконайтеся, що в вас є наступний набір залежностей у pom.xml (або build.gradle):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Ці залежності додають підтримку ресурсного сервера і Spring Security.
Налаштування ресурсного сервера
1. Конфігурація security-фільтрів
Створіть клас конфігурації для Spring Security:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/public/**").permitAll() // Відкриті ресурси
.antMatchers("/admin/**").hasRole("ADMIN") // Тільки для адмінів
.antMatchers("/user/**").hasRole("USER") // Тільки для користувачів
.anyRequest().authenticated() // Усі інші вимагають аутентифікації
.and()
.oauth2ResourceServer()
.jwt(); // Використовуємо JWT для перевірки токена
}
}
Тут ми визначаємо:
- Які ендпоінти є публічними.
- Які ресурси вимагають певних ролей.
- Налаштовуємо OAuth2 ресурсний сервер з використанням JWT.
2. Конфігурація токенів JWT
Додайте в application.yml (або application.properties) параметри, щоб вказати, де шукати публічний ключ для перевірки підпису токенів JWT:
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://auth-server.example.com/realms/myrealm
# Тут має бути URL вашого сервера авторизації (Issuer URI)
Параметр issuer-uri каже Spring Security, де знаходиться сервер авторизації (наприклад, Keycloak або Auth0), щоб витягти інформацію про конфігурацію токенів.
Приклад захищеного контролера
Давайте створимо REST контролер, який демонструє використання ролей і областей (scopes).
@RestController
@RequestMapping("/api")
public class ResourceController {
@GetMapping("/public")
public String publicEndpoint() {
return "Це публічний ресурс, доступний усім!";
}
@GetMapping("/user/hello")
public String userEndpoint(@AuthenticationPrincipal Jwt jwt) {
return "Привіт, користувачу " + jwt.getClaimAsString("preferred_username") + "!";
}
@GetMapping("/admin/dashboard")
public String adminEndpoint() {
return "Це адміністративний ресурс. Ласкаво просимо, великий Адмін!";
}
}
- Ендпоінт
/publicдоступний усім. - Ендпоінт
/user/helloвимагає наявності роліUSERі виводить інформацію з токена JWT (наприклад,preferred_username). - Ендпоінт
/admin/dashboardдоступний тільки адміністраторам.
Як перевірити роботу сервера?
- Крок 1: отримайте JWT токен. Зробіть це через сервер авторизації (наприклад, Keycloak або Auth0).
- Крок 2: надішліть запит з заголовком
Authorization: Bearer <ваш токен>до захищених ендпоінтів. - Крок 3: переконайтеся, що доступ надається або відхиляється в залежності від ролі та областей (scopes).
Керування ролями та правами
Ролі в OAuth2 і JWT відіграють ключову роль у наданні доступу до ресурсів. Наприклад, роль ROLE_ADMIN дає доступ до адміністративних ресурсів, а ROLE_USER — до користувацьких.
Токен JWT може включати області (scopes) і ролі як додаткові claims. Приклад структури токена:
{
"sub": "user123",
"scope": "read write",
"roles": ["USER", "ADMIN"],
"exp": 1698777600
}
Як перевіряти ролі в Spring? Spring Security автоматично перетворює roles у токені в авторизацію. Ви можете використовувати анотації:
@PreAuthorize("hasRole('ADMIN')")
@GetMapping("/secure/admin")
public String securedAdminEndpoint() {
return "Тільки для адмінів!";
}
Типові помилки й їх виправлення
- Помилка "403 Forbidden" при доступі з валідним токеном — швидше за все, у вас неправильно налаштовані ролі або області. Переконайтеся, що ролі, вказані в токені, відповідають очікуваним.
- Помилка перевірки підпису JWT — зазвичай це означає, що ваш ресурсний сервер не зміг отримати публічний ключ від сервера авторизації. Перевірте параметр
issuer-uriі переконайтеся, що сервер авторизації доступний. - Термін дії токена минув — переконайтеся, що ваші клієнти використовують Refresh токени для оновлення токенів доступу.
Застосування в реальному житті
Використання OAuth2 і JWT для захисту ресурсів забезпечує надійну і масштабовану безпеку для мікросервісних архітектур. Цей підхід використовується в багатьох реальних проєктах, починаючи від корпоративних додатків до платформ соціальної аутентифікації.
Наступного разу, коли зайдете на сайт і побачите кнопку "Увійти через Google", ви вже знаєте, що там працює OAuth2.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ