Каждое приложение, будь то гигантский онлайн-магазин или небольшой сервис заметок, имеет определенные ресурсы, которые требуют защиты: это могут быть данные пользователей, конфиденциальная информация или операции, изменяющие состояние системы. И наша задача как разработчиков — сделать эти ресурсы доступными только для тех, кто имеет право на доступ.
Без адекватного уровня защиты любой человек с базовым программным обеспечением (да, мы смотрим в сторону 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 контроллер, который демонстрирует использование ролей и областей.
@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: убедитесь, что доступ предоставляется или отклоняется в зависимости от роли и области.
Управление ролями и правами
Роли в 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.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ