Пример на Spring Boot 2.x
Spring Boot 2.x предусматривает возможность полноценно использовать автоконфигурацию для настройки входа в систему через OAuth 2.0.
В этом разделе показано, как сконфигурировать пример кода для входа в систему в OAuth 2.0, используя Google в качестве поставщика аутентификации, а также рассмотрены следующие темы:
-
Начальная настройка
-
Настройка URI для переадресации
-
Конфигурируем файл application.yml
-
<Загрузка приложения
Initial setup
Чтобы использовать систему аутентификации Google в OAuth 2.0 для входа в систему, необходимо настроить проект в Google API Console для получения учетных данных OAuth 2.0.
Следуйте инструкциям на странице OpenID Connect, начиная с раздела "Настройка OAuth 2.0".
После выполнения инструкции по "Получению учетных данных OAuth 2.0" должен появиться новый клиент OAuth с учетными данными, состоящими из идентификатора клиента и секрета клиента.
Настройка URI для переадресации
URI для переадресации – это путь в приложении, на который перенаправляется пользовательский агент конечного пользователя после аутентификации в Google и предоставления доступа к OAuth-клиенту (созданного на предыдущем этапе) на странице Согласия.
В подразделе "Установка URI для переадресации" убедитесь, что в поле авторизованных URI для переадресации установлено значение localhost:8080/login/oauth2/code/google
.
{baseUrl}/login/oauth2/code/{registrationId}
. RegistrationId – это уникальный идентификатор для ClientRegistration
.URI
для redirect-uri
.Конфигурируем файл application.yml
Теперь, когда получен новый OAuth-клиент через Google, необходимо сконфигурировать приложение на использование OAuth-клиента для потока аутентификации. Для этого:
-
Перейдите в
application.yml
и установите следующую конфигурацию:spring: security: oauth2: client: registration: google: client-id: google-client-id client-secret: google-client-secret
Свойства OAuth-клиентаspring.security.oauth2.client.registration
– это базовый префикс свойств для свойств OAuth-клиента.- После префикса базового свойства следует идентификатор для
ClientRegistration
, например google.
-
Замените значения в свойствах
client-id
иclient-secret
на учетные данные OAuth 2.0, которые были созданы ранее.
Загрузка приложения
Запустите пример Spring Boot 2.x и перейдите на localhost:8080
. Затем вы будете перенаправлены на автоматически созданную стандартную страницу входа в систему, на которой отображается ссылка для Google.
Нажмите на ссылку Google, после чего вы будете перенаправлены в Google для аутентификации.
После аутентификации с помощью учетных данных аккаунта Google на следующей странице появится экран Согласия. На экране "Согласие" будет предложено разрешить или запретить доступ к OAuth-клиенту, который был создан ранее. Нажмите "Разрешить", чтобы разрешить OAuth-клиенту доступ к вашему адресу электронной почты и основной информации профиля.
На этом этапе OAuth-клиент получает ваш адрес электронной почты и основную информацию о профиле из конечной точки UserInfo и устанавливает аутентифицированную сессию.
Отображения свойств в Spring Boot 2.x
В следующей таблице описано отображение свойств Spring Boot 2.x OAuth Client на свойства ClientRegistration
.
Spring Boot 2.x | ClientRegistration |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ClientRegistration
можно изначально сконфигурировать с помощью обнаружения конечной точки конфигурации поставшика OpenID Connect или конечной точки метаданных сервера авторизации, задав свойство spring.security.oauth2.client.provider.[providerId].issuer-uri
.CommonOAuth2Provider
CommonOAuth2Provider
предопределяет набор стандартных свойств клиента для ряда известных поставщиков: Google, GitHub, Facebook и Okta.
Например, authorization-uri
, token-uri
и user-info-uri
не часто меняются для какого-либо поставщика. Поэтому имеет смысл указать значения по умолчанию, чтобы сократить требуемую конфигурацию.
Как было показано ранее, когда мы настраивали клиент Google, обязательными являются только свойства client-id
и client-secret
.
В следующем листинге приведен пример:
spring:
security:
oauth2:
client:
registration:
google:
client-id: google-client-id
client-secret: google-client-secret
registrationId
(google
) совпадает с enum
GOOGLE
(без учета регистра) в CommonOAuth2Provider
.Для случаев, когда необходимо задать другой registrationId
, например, google-login
, все равно можно использовать автоматическое определение свойств клиента по умолчанию, сконфигурировав свойство provider
.
В следующем листинге приведен пример:
spring:
security:
oauth2:
client:
registration:
google-login:
provider: google
client-id: google-client-id
client-secret: google-client-secret
- Для
registrationId
установлено значениеgoogle-login
. - Свойство
provider
установлено в значениеgoogle
, что позволит использовать автоматическое определение свойств клиента по умолчанию, установленное вCommonOAuth2Provider.GOOGLE.getBuilder()
.
Конфигурирование кастомных свойств поставщика
Некоторые поставщики OAuth 2.0 поддерживают работу в режиме коллективной аренды, что приводит к созданию различных конечных точек протоколов для каждого арендатора (или поддомена).
Например, OAuth-клиент, зарегистрированный в Okta, присваивается определенному поддомену и имеет свои собственные конечные точки протоколов.
Для таких случаев Spring Boot 2.x предусматривает следующее базовое свойство для конфигурирования кастомных свойств поставщика: spring.security.oauth2.client.provider.[providerId]
.
В следующем листинге приведен пример:
spring:
security:
oauth2:
client:
registration:
okta:
client-id: okta-client-id
client-secret: okta-client-secret
provider:
okta:
authorization-uri: https://your-subdomain.oktapreview.com/oauth2/v1/authorize
token-uri: https://your-subdomain.oktapreview.com/oauth2/v1/token
user-info-uri: https://your-subdomain.oktapreview.com/oauth2/v1/userinfo
user-name-attribute: sub
jwk-set-uri: https://your-subdomain.oktapreview.com/oauth2/v1/keys
- Базовое свойство
(spring.security.oauth2.client.provider.okta
) позволяет кастомно конфигурировать местоположение конечных точек протоколов.
Переопределение автоконфигурации Spring Boot 2.x
Класс автоконфигурации Spring Boot 2.x для поддержки OAuth-клиента – OAuth2ClientAutoConfiguration
.
Он выполняет следующие задачи:
-
Регистрирует
@Bean
дляClientRegistrationRepository
, состоящий из экземпляра(ов)ClientRegistration
из сконфигурированных свойств OAuth-клиента. -
Регистрирует
@Bean
дляSecurityFilterChain
и активирует авторизацию в OAuth 2.0 черезhttpSecurity.oauth2Login()
.
Если необходимо переопределить автоконфигурацию под конкретные потребности, то сделать это можно следующими способами:
-
Регистрируем @Bean для ClientRegistrationRepository
-
Регистрируем @Bean для SecurityFilterChain
-
Полное переопределение автоконфигурации
Регистрируем @Bean для ClientRegistrationRepository
В следующем примере показано, как зарегистрировать @Bean
для ClientRegistrationRepository
:
@Configuration
public class OAuth2LoginConfig {
@Bean
public ClientRegistrationRepository clientRegistrationRepository() {
return new InMemoryClientRegistrationRepository(this.googleClientRegistration());
}
private ClientRegistration googleClientRegistration() {
return ClientRegistration.withRegistrationId("google")
.clientId("google-client-id")
.clientSecret("google-client-secret")
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.redirectUri("{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();
}
}
@Configuration
class OAuth2LoginConfig {
@Bean
fun clientRegistrationRepository(): ClientRegistrationRepository {
return InMemoryClientRegistrationRepository(googleClientRegistration())
}
private fun googleClientRegistration(): ClientRegistration {
return ClientRegistration.withRegistrationId("google")
.clientId("google-client-id")
.clientSecret("google-client-secret")
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.redirectUri("{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()
}
}
Регистрируем @Bean для SecurityFilterChain
В следующем примере показано, как зарегистрировать @Bean
для SecurityFilterChain
с использованием аннотации @EnableWebSecurity
и активировать авторизацию в OAuth 2.0 через httpSecurity.oauth2Login()
:
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.anyRequest().authenticated()
)
.oauth2Login(withDefaults());
return http.build();
}
}
@EnableWebSecurity
class OAuth2LoginSecurityConfig {
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
http {
authorizeRequests {
authorize(anyRequest, authenticated)
}
oauth2Login { }
}
return http.build()
}
}
Полное переопределение автоконфигурации
В следующем примере показано, как полностью переопределить автоконфигурацию, зарегистрировав @Bean
для ClientRegistrationRepository
и @Bean
для SecurityFilterChain
.
@Configuration
public class OAuth2LoginConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.anyRequest().authenticated()
)
.oauth2Login(withDefaults());
return http.build();
}
@Bean
public ClientRegistrationRepository clientRegistrationRepository() {
return new InMemoryClientRegistrationRepository(this.googleClientRegistration());
}
private ClientRegistration googleClientRegistration() {
return ClientRegistration.withRegistrationId("google")
.clientId("google-client-id")
.clientSecret("google-client-secret")
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.redirectUri("{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();
}
}
@Configuration
class OAuth2LoginConfig {
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
http {
authorizeRequests {
authorize(anyRequest, authenticated)
}
oauth2Login { }
}
return http.build()
}
@Bean
fun clientRegistrationRepository(): ClientRegistrationRepository {
return InMemoryClientRegistrationRepository(googleClientRegistration())
}
private fun googleClientRegistration(): ClientRegistration {
return ClientRegistration.withRegistrationId("google")
.clientId("google-client-id")
.clientSecret("google-client-secret")
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.redirectUri("{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()
}
}
Конфигурация на базе Java без Spring Boot 2.x
Если использовать Spring Boot 2.x не представляется возможным, но нужно настроить одного из предопределенных поставщиков в CommonOAuth2Provider
(например, Google), примените следующую конфигурацию:
@EnableWebSecurity
public class OAuth2LoginConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.anyRequest().authenticated()
)
.oauth2Login(withDefaults());
return http.build();
}
@Bean
public ClientRegistrationRepository clientRegistrationRepository() {
return new InMemoryClientRegistrationRepository(this.googleClientRegistration());
}
@Bean
public OAuth2AuthorizedClientService authorizedClientService(
ClientRegistrationRepository clientRegistrationRepository) {
return new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository);
}
@Bean
public OAuth2AuthorizedClientRepository authorizedClientRepository(
OAuth2AuthorizedClientService authorizedClientService) {
return new AuthenticatedPrincipalOAuth2AuthorizedClientRepository(authorizedClientService);
}
private ClientRegistration googleClientRegistration() {
return CommonOAuth2Provider.GOOGLE.getBuilder("google")
.clientId("google-client-id")
.clientSecret("google-client-secret")
.build();
}
}
@EnableWebSecurity
open class OAuth2LoginConfig {
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
http {
authorizeRequests {
authorize(anyRequest, authenticated)
}
oauth2Login { }
}
return http.build()
}
@Bean
open fun clientRegistrationRepository(): ClientRegistrationRepository {
return InMemoryClientRegistrationRepository(googleClientRegistration())
}
@Bean
open fun authorizedClientService(
clientRegistrationRepository: ClientRegistrationRepository?
): OAuth2AuthorizedClientService {
return InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository)
}
@Bean
open fun authorizedClientRepository(
authorizedClientService: OAuth2AuthorizedClientService?
): OAuth2AuthorizedClientRepository {
return AuthenticatedPrincipalOAuth2AuthorizedClientRepository(authorizedClientService)
}
private fun googleClientRegistration(): ClientRegistration {
return CommonOAuth2Provider.GOOGLE.getBuilder("google")
.clientId("google-client-id")
.clientSecret("google-client-secret")
.build()
}
}
<http auto-config="true">
<intercept-url pattern="/**" access="authenticated"/>
<oauth2-login authorized-client-repository-ref="authorizedClientRepository"/>
</http>
<client-registrations>
<client-registration registration-id="google"
client-id="google-client-id"
client-secret="google-client-secret"
provider-id="google"/>
</client-registrations>
<b:bean id="authorizedClientService"
class="org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService"
autowire="constructor"/>
<b:bean id="authorizedClientRepository"
class="org.springframework.security.oauth2.client.web.AuthenticatedPrincipalOAuth2AuthorizedClientRepository">
<b:constructor-arg ref="authorizedClientService"/>
</b:bean>
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ