Я интегрирую OAuth2 (Google в качестве поставщика OIDC) в существующее приложение Spring Boot, которое в настоящее время использует простой DaoAuthenticationProvider
. Я внес изменения, чтобы интеграция OAuth работала, но теперь мне нужно предоставить переключатель конфигурации, чтобы отключить ее в определенных средах (вернуться к использованию старой аутентификации на основе базы данных).
Конфигурация для использования OAuth2 выглядит следующим образом:
spring:
security:
oauth2:
client:
registration:
google:
client-id: 1234567890-1a2b3c4d5e6f7g8h9i0j.apps.googleusercontent.com
client-secret: ABCDEF-1234-OU812_XYZZY
Мой класс @Configuration
для аутентификации выглядит так:
@Configuration
@EnableWebSecurity
public class GoogleOIDCSecurityConfiguration {
@Bean
OidcUserService oidcUserService() {
Set<String> scopes = Set.of(
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/userinfo.profile"
);
OidcUserService service = new OidcUserService();
service.setAccessibleScopes(scopes);
return service;
}
@Bean
SecurityFilterChain oidcFilterChain(HttpSecurity http, OidcUserService userService) throws Exception {
http
.authorizeHttpRequests(this::configureAuthorization)
.oauth2Login(c -> configureOAuth2(c, userService))
.logout(this::configureLogout)
;
return http.build();
}
protected void configureAuthorization(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry authorize) {
authorize
.dispatcherTypeMatchers(DispatcherType.FORWARD, DispatcherType.INCLUDE, DispatcherType.ERROR).permitAll()
.requestMatchers("/*/*.js", "/*/*/*.js", "/css/**", "/lib/**", "/assets/**", "favicon.ico").permitAll()
.requestMatchers("/", LOGIN_PAGE, INVALID_SESSION_PAGE, LOGOUT_PAGE).permitAll()
.requestMatchers("/foo/**").hasAnyRole(Roles.FOO)
.requestMatchers("/admin/**").hasRole(Roles.ADMIN)
.anyRequest().authenticated();
}
private void configureOAuth2(OAuth2LoginConfigurer<HttpSecurity> oauthLogin, OidcUserService userService) {
oauthLogin
.userInfoEndpoint(endpoint -> endpoint.oidcUserService(userService));
}
}
Моя первая попытка условно отключить его заключалась в том, чтобы установить client-id
пустым в определенных профилях и использовать @ConditionalOnProperty
для ссылки на этот ключ. Это не удается из-за исключения проверки, говорящего, что client-id
не может быть пустым. Кажется, что наличие чего-либо под spring.security.oauth2.client.registration.*
запускает автоматическую настройку OAuth.
Что мне нужно сделать, так это найти способ полностью отключить автоматическую настройку для любых клиентов OAuth, но только в определенных профилях (или с использованием определенного свойства конфигурации).
Почему бы вам не поместить все свои свойства конфигурации и компоненты OAuth2 в этот профиль?
# properties for all profiles here
---
spring:
config:
activate:
on-profile:
- oauth2
security:
oauth2:
client:
registration:
google:
client-id: 1234567890-1a2b3c4d5e6f7g8h9i0j.apps.googleusercontent.com
client-secret: ABCDEF-1234-OU812_XYZZY
@Profile("oauth2")
@Configuration
@EnableWebSecurity
public class GoogleOIDCSecurityConfiguration {
...
}
@Profile("legacy")
@Configuration
@EnableWebSecurity
public class LegacySecurityConfiguration {
...
}
Обратите внимание, что вы можете «автоматически подписаться», установив этот профиль oauth2 активным по умолчанию. В Maven профиль activeByDefault
отключается, если явно задан хотя бы другой профиль (поэтому вам также придется установить его явно, если вы хотите, чтобы он был связан с другим профилем). В Gradle может быть аналогичная функция. В вашем случае я бы установил профиль oauth2
активным по умолчанию, а также определил бы профиль legacy
с deps и conf для более старой системы, чтобы у меня одновременно был только один из двух conf и deps.
Мы используем «локальный» профиль во всех средах, чтобы можно было легко переопределить его с помощью application-local.yml
(в ближайшее время это не изменится), поэтому я не думаю, что трюк с созданием oauth2
активного профиля по умолчанию сработает.
Не путайте профили Maven (или Gradle) и Spring (local
— это профиль Spring). Внимательно посмотрите на отредактированный ответ для ручной синхронизации между профилями Maven и Spring. Также обратите внимание, что каждый из этих профилей Maven можно использовать «локально»: oauth2
не активируя профиль Maven (или с явной активацией) и legacy
только с явной активацией (отключив oauth2
, если также не активировать явно, но зачем это делать?)
Я удаляю часть ответа, касающуюся Maven, поскольку она не имеет прямого отношения к ответу на вопрос. Интересная информация, но я чувствую, что это сбивает с толку полезный ответ. Мне также принципиально не нравится необходимость сборки отдельно для разных сред. Создайте один раз, разверните много.
Жаль, что я вас запутал, потому что, вероятно, было бы предпочтительнее, чтобы у вас одновременно был только один набор зависимостей от пути к классам (и это требует некоторой настройки системы сборки). Лучший способ отключить стартер Spring Boot — это удалить его из пути к классам: больше никаких транзитивных зависимостей и никакой автоматической настройки.
Хороший улов на csrf.dissble()
звонок. Это была ошибка копирования и вставки при написании нового класса конфигурации OAuth2. Я удалил его из кода в вопросе.
Вероятно, было бы более полезно добавить аналог Gradle.