Аутентификация (OAuth 2.0) в Spring Security
Аутентификация нужна для того, чтобы твоё приложение было безопасным. Представь, что ты сделал крутое приложение, в котором пользователи могут делиться своими фотографиями. Но любой человек может зайти в приложение и удалить чужие фотки или оставить неприятные комментарии. Чтобы этого не произошло, нужно сделать аутентификацию.
Для аутентификации часто используется протокол OAuth 2.0. Я расскажу, как настроить аутентификацию через OAuth 2.0 в Spring Security. Это популярный инструмент для создания безопасных приложений на Java.
Основы Spring Security
Spring Security помогает защитить приложение от неавторизованного доступа. Он проверяет, кто пытается получить доступ к ресурсам приложения. Если пользователь не прошёл аутентификацию, Spring Security не пустит его.
Spring Security состоит из фильтров, которые перехватывают запросы и проверяют аутентификацию. Также в нём есть специальные классы для работы с пользователями и ролями.
Фильтры Spring Security работают следующим образом:
- Перехватывают входящий HTTP-запрос
- Проверяют, аутентифицирован ли пользователь
- Если пользователь не аутентифицирован, перенаправляют на страницу логина
- Если аутентифицирован, проверяют авторизацию - имеет ли пользователь доступ к данному URL
- Если доступ разрешен, обрабатывают запрос дальше
- Если доступ запрещен, возвращают ошибку 403 (доступ запрещен)
Классы для работы с пользователями в Spring Security:
- UserDetails - интерфейс, описывающий пользователя
- UserDetailsService - загружает данные о пользователе
- User - реализация UserDetails на основе класса-модели пользователя
Что такое OAuth 2.0
OAuth 2.0 - это протокол для аутентификации. Он позволяет войти в приложение через другие сервисы, например через аккаунт Google или ВКонтакте.
OAuth 2.0 использует специальные токены для аутентификации. Клиент (твоё приложение) получает от провайдера (например, Google) токен доступа после аутентификации пользователя. Потом приложение использует этот токен для проверки, аутентифицирован ли пользователь.
- Ресурс (Resource) - данные, к которым нужен доступ. Например, фотографии пользователя.
- Владелец ресурса (Resource Owner) - пользователь, который может предоставить доступ к ресурсу.
- Клиент (Client) - приложение, которое хочет получить доступ к ресурсу.
- Авторизационный сервер (Authorization Server) - сервер, который аутентифицирует владельца и выдаёт токены доступа.
- Потребитель ресурса (Resource Server) - сервер, на котором хранятся ресурсы. Проверяет токены доступа.
Процесс аутентификации в OAuth 2.0:
- Пользователь переходит на сайт и видит кнопку "Войти через Google"
- Пользователь нажимает кнопку
- Приложение делает запрос авторизации к Google
- Google просит пользователя аутентифицироваться и разрешить доступ
- Пользователь вводит данные и разрешает доступ к ресурсам
- Google возвращает приложению токен доступа
- Приложение использует токен для доступа к данным пользователя
Настройка Spring для OAuth 2.0
Чтобы настроить OAuth 2.0 в Spring, нужно:
Это можно сделать на сайте start.spring.io. Выбираем Maven или Gradle, Java, версию Spring Boot. Указываем artifact, group, packagе. Генерируем проект.
Эти зависимости подключают Spring Security и клиент OAuth2. Добавляем их в pom.xml или build.gradle.
Нужно указать clientRegistrationRepository для регистрации клиентов OAuth2.
@EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .and() .oauth2Login(); } @Bean public ClientRegistrationRepository clientRegistrationRepository() { return new InMemoryClientRegistrationRepository(this.googleClientRegistration()); } private ClientRegistration googleClientRegistration() { return ClientRegistration .withRegistrationId("google") .clientId("123456") .clientSecret("secret") .clientAuthenticationMethod(ClientAuthenticationMethod.BASIC) .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) .redirectUriTemplate("{baseUrl}/login/oauth2/code/{registrationId}") .scope("openid", "profile", "email", "address", "phone") .authorizationUri("https://accounts.google.com/o/oauth2/v2/auth") .tokenUri("https://www.googleapis.com/oauth2/v4/token") .userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo") .userNameAttributeName(IdTokenClaimNames.SUB) .jwkSetUri("https://www.googleapis.com/oauth2/v3/certs") .clientName("Google") .build(); } }
Настройка провайдера авторизации
Чтобы использовать OAuth 2.0, нужно зарегистрировать приложение в провайдере авторизации, например в Google.
После регистрации ты получишь клиентский ID и секретный ключ. Их нужно будет указать в конфигурации Spring Security.
Регистрируем приложение в Google:
- Заходим в Google Cloud Console, создаем новый проект
- Переходим в раздел "OAuth согласие экрана"
- Нажимаем "Создать согласия"
- Выбираем "Внешний" тип приложения
- Заполняем название приложения, его описание
- Указываем авторизированные JavaScript источники
- Сохраняем изменения
После этого на вкладке "Учетные данные" будут доступны Client ID и Client Secret - их и нужно указать в конфигурации Spring Security.
Работа с токенами
Когда пользователь войдёт через Google, твой клиент получит токен доступа от провайдера авторизации.
Потом этот токен будет использоваться для аутентификации пользователя. Токены также нужно периодически обновлять.
- Пользователь аутентифицируется в Google и разрешает доступ к данным
- Google формирует токен доступа и отправляет его в redirect_uri приложения в параметре code
- Приложение извлекает код из параметра code с redirect_uri
- Приложение делает POST запрос на endpoint token Google, передавая grant_type=authorization_code и code
- Google проверяет код и возвращает приложению токен доступа и refresh токен
- Приложение сохраняет токены и использует их для доступа к API
Обновление токена происходит аналогично, только вместо code используется refresh_token в запросе к Google.
Аутентификация с помощью OAuth 2.0
Чтобы аутентифицировать пользователя, Spring Security сделает редирект на страницу входа выбранного провайдера.
Например, для Google будет сформирован такой запрос:
https://accounts.google.com/o/oauth2/v2/auth? redirect_uri=http://myapp.com/login/oauth2/code/google client_id=123456 scope=openid%20profile%20email response_type=code state=foobar
- redirect_uri - адрес для возврата в приложение
- client_id - идентификатор приложения в Google
- scope - запрашиваемые разрешения
- response_type - указывает, что нужен authorization code
- state - случайная строка для защиты от CSRF
После успешной аутентификации пользователь будет перенаправлен обратно в приложение уже залогиненным.
Теперь Spring Security будет использовать токены из OAuth для проверки авторизации при обращении к защищённым ресурсам.
Для этого он будет добавлять в HTTP-запросы заголовок Authorization: Bearer [token], где [token] - текущий access token.
Выводы
Аутентификация - важная часть любого приложения. Благодаря Spring Security и OAuth 2.0 ты можешь легко реализовать вход через популярные сервисы и обезопасить своё приложение от неавторизованного доступа.