HttpSecurity.oauth2Login() предусматривает ряд вариантов конфигурации для настройки авторизации в OAuth 2.0. Основные варианты конфигурации сгруппированы по их аналогам для конечных точек протокола.

Например, oauth2Login().authorizationEndpoint() позволяет сконфигурировать конечную точку авторизации, тогда как oauth2Login().tokenEndpoint() позволяет сконфигурировать конечную точку токенов.

В следующем коде показан пример:

Расширенная конфигурация входа в систему в OAuth2
Java
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {
	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			.oauth2Login(oauth2 -> oauth2
			    .authorizationEndpoint(authorization -> authorization
			            ...
			    )
			    .redirectionEndpoint(redirection -> redirection
			            ...
			    )
			    .tokenEndpoint(token -> token
			            ...
			    )
			    .userInfoEndpoint(userInfo -> userInfo
			            ...
			    )
			);
		return http.build();
	}
}
Kotlin
@EnableWebSecurity
class OAuth2LoginSecurityConfig {
    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            oauth2Login {
                authorizationEndpoint {
                    ...
                }
                redirectionEndpoint {
                    ...
                }
                tokenEndpoint {
                    ...
                }
                userInfoEndpoint {
                    ...
                }
            }
        }
        return http.build()
    }
}

Основной целью создания oauth2Login() на основе DSL было тесное соответствие именованию, определенному в спецификациях.

Фреймворк авторизации OAuth 2.0 определяет конечные точки протоколов следующим образом:

В процессе авторизации используются две конечные точки сервера авторизации (HTTP-ресурсы):

  • Конечная точка авторизации: Используется клиентом для получения авторизации от владельца ресурса через перенаправление пользовательского агента.

  • Конечная точка токенов: Используется клиентом для обмена разрешения на доступ на токен доступа, обычно при аутентификации клиента.

А также одна конечная точка клиентов:

  • Конечная точка переадресации: Используется сервером авторизации для возврата клиенту ответов, содержащих учетные данные авторизации, через пользовательского агента владельца ресурса.

Спецификация OpenID Connect Core 1.0 определяет конечную точку UserInfo следующим образом:

Конечная точка UserInfo является защищенным ресурсом OAuth 2.0, который возвращает данные об аутентифицированном конечном пользователе. Чтобы получить запрошенные данные о конечном пользователе, клиент делает запрос к конечной точке UserInfo, используя токен доступа, полученный через аутентификацию OpenID Connect. Эти заявленные значения обычно представлены объектом JSON, который содержит набор пар "имя-значение" для заявленных значений.

В следующем коде продемонстрированы все параметры конфигурации, доступные для oauth2Login() на основе DSL:

Параметры конфигурации авторизации в OAuth2
Java
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {
	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			.oauth2Login(oauth2 -> oauth2
			    .clientRegistrationRepository(this.clientRegistrationRepository())
			    .authorizedClientRepository(this.authorizedClientRepository())
			    .authorizedClientService(this.authorizedClientService())
			    .loginPage("/login")
			    .authorizationEndpoint(authorization -> authorization
			        .baseUri(this.authorizationRequestBaseUri())
			        .authorizationRequestRepository(this.authorizationRequestRepository())
			        .authorizationRequestResolver(this.authorizationRequestResolver())
			    )
			    .redirectionEndpoint(redirection -> redirection
			        .baseUri(this.authorizationResponseBaseUri())
			    )
			    .tokenEndpoint(token -> token
			        .accessTokenResponseClient(this.accessTokenResponseClient())
			    )
			    .userInfoEndpoint(userInfo -> userInfo
			        .userAuthoritiesMapper(this.userAuthoritiesMapper())
			        .userService(this.oauth2UserService())
			        .oidcUserService(this.oidcUserService())
			    )
			);
		return http.build();
	}
}
Kotlin
@EnableWebSecurity
class OAuth2LoginSecurityConfig {
    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            oauth2Login {
                clientRegistrationRepository = clientRegistrationRepository()
                authorizedClientRepository = authorizedClientRepository()
                authorizedClientService = authorizedClientService()
                loginPage = "/login"
                authorizationEndpoint {
                    baseUri = authorizationRequestBaseUri()
                    authorizationRequestRepository = authorizationRequestRepository()
                    authorizationRequestResolver = authorizationRequestResolver()
                }
                redirectionEndpoint {
                    baseUri = authorizationResponseBaseUri()
                }
                tokenEndpoint {
                    accessTokenResponseClient = accessTokenResponseClient()
                }
                userInfoEndpoint {
                    userAuthoritiesMapper = userAuthoritiesMapper()
                    userService = oauth2UserService()
                    oidcUserService = oidcUserService()
                }
            }
        }
        return http.build()
    }
}

В дополнение к oauth2Login() на основе DSL также поддерживается XML-конфигурация.

В следующем коде показаны все параметры конфигурации, доступные в <пространстве имен безопасности:< p>

Параметры XML-конфигурации входа в систему в OAuth2
<http>
	<oauth2-login client-registration-repository-ref="clientRegistrationRepository"
				  authorized-client-repository-ref="authorizedClientRepository"
				  authorized-client-service-ref="authorizedClientService"
				  authorization-request-repository-ref="authorizationRequestRepository"
				  authorization-request-resolver-ref="authorizationRequestResolver"
				  access-token-response-client-ref="accessTokenResponseClient"
				  user-authorities-mapper-ref="userAuthoritiesMapper"
				  user-service-ref="oauth2UserService"
				  oidc-user-service-ref="oidcUserService"
				  login-processing-url="/login/oauth2/code/*"
				  login-page="/login"
				  authentication-success-handler-ref="authenticationSuccessHandler"
				  authentication-failure-handler-ref="authenticationFailureHandler"
				  jwt-decoder-factory-ref="jwtDecoderFactory"/>
</http>

В следующих разделах более подробно описан каждый из доступных вариантов конфигурации:

  • Страница входа в систему в OAuth 2.0

  • Конечная точка переадресации

  • Конечная точка UserInfo

  • Верификация сигнатуры ID токена

  • Выход из системы OpenID Connect 1.0

Страница входа в систему в OAuth 2.0

По умолчанию страница авторизации в OAuth 2.0 автоматически генерируется через DefaultLoginPageGeneratingFilter. Страница авторизации по умолчанию отображает каждый сконфигурированный OAuth-клиент с его ClientRegistration.clientName в виде ссылки, по которой можно инициировать запрос на авторизацию (или вход в систему OAuth 2.0).

Чтобы DefaultLoginPageGeneratingFilter отображал ссылки для сконфигурированных OAuth-клиентов, зарегистрированный ClientRegistrationRepository должен также реализовывать Iterable<ClientRegistration>. См. InMemoryClientRegistrationRepository для справки.

Назначение ссылки для каждого OAuth-клиента по умолчанию следующее:

OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI + "/{registrationId}"

В следующей строке приведен пример:

<a href="/oauth2/authorization/google">Google</a>

Чтобы переопределить стандартную страницу входа в систему, сконфигурируйте oauth2Login().loginPage() и (необязательно) oauth2Login().authorizationEndpoint().baseUri().

В следующем листинге приведен пример:

Конфигурация страницы входа в систему OAuth2
Java
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {
	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			.oauth2Login(oauth2 -> oauth2
			    .loginPage("/login/oauth2")
			    ...
			    .authorizationEndpoint(authorization -> authorization
			        .baseUri("/login/oauth2/authorization")
			        ...
			    )
			);
		return http.build();
	}
}
Kotlin
@EnableWebSecurity
class OAuth2LoginSecurityConfig {
    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            oauth2Login {
                loginPage = "/login/oauth2"
                authorizationEndpoint {
                    baseUri = "/login/oauth2/authorization"
                }
            }
        }
        return http.build()
    }
}
Xml
<http>
	<oauth2-login login-page="/login/oauth2"
				  ...
    />
</http>
Вам необходимо указать для аннотации @Controller параметр @RequestMapping("/login/oauth2"), который сможет визуализировать кастомную страницу входа.

Как отмечалось ранее, добавлять в конфигурацию oauth2Login().authorizationEndpoint().baseUri() необязательно. Однако если вы решите индивидуализировать настройки, убедитесь, что ссылка на каждый OAuth-клиент соответствует authorizationEndpoint().baseUri().

В следующей строке приведен пример:

<a href="/login/oauth2/authorization/google">Google</a>

Конечная точка переадресации

Конечная точка переадресации используется сервером авторизации для возврата ответа авторизации (который содержит учетные данные авторизации) клиенту через пользовательского агента владельца ресурса.

При входе в систему в OAuth 2.0 используется разрешение с кодом доступа. Поэтому учетными данными авторизации является код авторизации.

По умолчанию ответ на запрос на авторизацию для baseUri (конечная точка переадресации) – это /login/oauth2/code/*, который определен в OAuth2LoginAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI.

Если необходимо настроить конечную точку BaseUri ответа авторизации, сконфигурируйте его, как показано в следующем примере:

Конфигурация конечной точки переадресации
Java
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {
    @Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			.oauth2Login(oauth2 -> oauth2
			    .redirectionEndpoint(redirection -> redirection
			        .baseUri("/login/oauth2/callback/*")
			        ...
			    )
			);
		return http.build();
	}
}
Kotlin
@EnableWebSecurity
class OAuth2LoginSecurityConfig {
    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            oauth2Login {
                redirectionEndpoint {
                    baseUri = "/login/oauth2/callback/*"
                }
            }
        }
        return http.build()
    }
}
Xml
<http>
	<oauth2-login login-processing-url="/login/oauth2/callback/*"
				  ...
    />
</http>

Также необходимо удостовериться, что ClientRegistration.redirectUri соответствует кастомному ответу на запрос на авторизацию для baseUri.

В следующем листинге приведен пример:

Java
return CommonOAuth2Provider.GOOGLE.getBuilder("google")
	.clientId("google-client-id")
	.clientSecret("google-client-secret")
	.redirectUri("{baseUrl}/login/oauth2/callback/{registrationId}")
	.build();
Kotlin
return CommonOAuth2Provider.GOOGLE.getBuilder("google")
    .clientId("google-client-id")
    .clientSecret("google-client-secret")
    .redirectUri("{baseUrl}/login/oauth2/callback/{registrationId}")
    .build()

Конечная точка UserInfo

Конечная точка UserInfo содержит ряд вариантов конфигурации, описанных в следующих подразделах:

  • Отображение полномочий пользователя

  • OAuth 2.0 UserService

  • OpenID Connect 1.0 UserService

Отображение полномочий пользователя

После успешной аутентификации пользователя через поставщика OAuth 2.0, OAuth2User.getAuthorities() (или OidcUser.getAuthorities()) может быть отображен на новый набор экземпляров GrantedAuthority, которые будут переданы в OAuth2AuthenticationToken при завершении аутентификации.

OAuth2AuthenticationToken.getAuthorities() используется для авторизации запросов, например, в hasRole('USER') или hasRole('ADMIN').

Существует несколько вариантов отображения полномочий пользователя:

  • Использование GrantedAuthoritiesMapper

  • Стратегия на основе делегирования с помощью OAuth2UserService

Использование GrantedAuthoritiesMapper

Указываем реализацию GrantedAuthoritiesMapper и конфигурируем ее, как показано в следующем примере:

Конфигурация отображения предоставленных полномочий
Java
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {
    @Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			.oauth2Login(oauth2 -> oauth2
			    .userInfoEndpoint(userInfo -> userInfo
			        .userAuthoritiesMapper(this.userAuthoritiesMapper())
			        ...
			    )
			);
		return http.build();
	}
	private GrantedAuthoritiesMapper userAuthoritiesMapper() {
		return (authorities) -> {
			Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
			authorities.forEach(authority -> {
				if (OidcUserAuthority.class.isInstance(authority)) {
					OidcUserAuthority oidcUserAuthority = (OidcUserAuthority)authority;
					OidcIdToken idToken = oidcUserAuthority.getIdToken();
					OidcUserInfo userInfo = oidcUserAuthority.getUserInfo();
					// Отображаем заявленные значения, найденные в idToken и/или userInfo,
					// на один или несколько GrantedAuthority и добавляем его в mappedAuthorities
				} else if (OAuth2UserAuthority.class.isInstance(authority)) {
					OAuth2UserAuthority oauth2UserAuthority = (OAuth2UserAuthority)authority;
					Map<String, Object> userAttributes = oauth2UserAuthority.getAttributes();
					// Отображаем атрибуты, найденные в userAttributes,
					// на один или несколько GrantedAuthority и добавляем его в mappedAuthorities
				}
			});
			return mappedAuthorities;
		};
	}
}
Kotlin
@EnableWebSecurity
class OAuth2LoginSecurityConfig {
    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            oauth2Login {
                userInfoEndpoint {
                    userAuthoritiesMapper = userAuthoritiesMapper()
                }
            }
        }
        return http.build()
    }
    private fun userAuthoritiesMapper(): GrantedAuthoritiesMapper = GrantedAuthoritiesMapper { authorities: Collection<GrantedAuthority> ->
        val mappedAuthorities = emptySet<GrantedAuthority>()
        authorities.forEach { authority ->
            if (authority is OidcUserAuthority) {
                val idToken = authority.idToken
                val userInfo = authority.userInfo
                // Отображаем заявленные значения, найденные в idToken и/или userInfo,
                // на один или несколько GrantedAuthority и добавляем его в mappedAuthorities
            } else if (authority is OAuth2UserAuthority) {
                val userAttributes = authority.attributes
                // Отображаем атрибуты, найденные в userAttributes,
                // на один или несколько GrantedAuthority и добавляем его в mappedAuthorities
            }
        }
        mappedAuthorities
    }
}
Xml
<http>
	<oauth2-login user-authorities-mapper-ref="userAuthoritiesMapper"
				  ...
    />
</http>

В качестве альтернативы можно зарегистрировать @Bean для GrantedAuthoritiesMapper, чтобы он автоматически применялся к конфигурации, как показано в следующем примере:

Конфигурация отображения полученных полномочий через бин
Java
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {
	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
		    .oauth2Login(withDefaults());
		return http.build();
	}
	@Bean
	public GrantedAuthoritiesMapper userAuthoritiesMapper() {
		...
	}
}
Kotlin
@EnableWebSecurity
class OAuth2LoginSecurityConfig {
    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            oauth2Login { }
        }
        return http.build()
    }
    @Bean
    fun userAuthoritiesMapper(): GrantedAuthoritiesMapper {
        ...
    }
}

Стратегия на основе делегирования с помощью OAuth2UserService

Эта стратегия является более продвинутой по сравнению с использованием GrantedAuthoritiesMapper, однако, она также более гибкая, поскольку дает доступ к OAuth2UserRequest и OAuth2User (при использовании OAuth 2.0 UserService) или OidcUserRequest и OidcUser (при использовании OpenID Connect 1.0 UserService).

OAuth2UserRequestOidcUserRequest) предоставляет доступ к связанному OAuth2AccessToken, который очень полезен в случаях, если делегирующему объекту необходимо получить информацию о разрешениях из защищенного ресурса, прежде чем он сможет отобразить кастомные полномочия для пользователя.

В следующем примере показано, как реализовать и сконфигурировать стратегию на основе делегирования, используя OpenID Connect 1.0 UserService:

Конфигурация OAuth2UserService
Java
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {
	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			.oauth2Login(oauth2 -> oauth2
			    .userInfoEndpoint(userInfo -> userInfo
			        .oidcUserService(this.oidcUserService())
			        ...
			    )
			);
		return http.build();
	}
	private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
		final OidcUserService delegate = new OidcUserService();
		return (userRequest) -> {
			// Делегируем полномочия стандартной реализации для загрузки пользователя
			OidcUser oidcUser = delegate.loadUser(userRequest);
			OAuth2AccessToken accessToken = userRequest.getAccessToken();
			Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
			// TODO
			// 1) Осуществляем выборку информации о полномочиях из защищенного ресурса, используя accessToken
			// 2) Map the authority information на один или несколько GrantedAuthority и добавляем его в mappedAuthorities
			// 3) Создаем копию oidcUser, но используем mappedAuthorities
			oidcUser = new DefaultOidcUser(mappedAuthorities, oidcUser.getIdToken(), oidcUser.getUserInfo());
			return oidcUser;
		};
	}
}
Kotlin
@EnableWebSecurity
class OAuth2LoginSecurityConfig  {
    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            oauth2Login {
                userInfoEndpoint {
                    oidcUserService = oidcUserService()
                }
            }
        }
        return http.build()
    }
    @Bean
    fun oidcUserService(): OAuth2UserService<OidcUserRequest, OidcUser> {
        val delegate = OidcUserService()
        return OAuth2UserService { userRequest ->
            // Делегируем полномочия стандартной реализации для загрузки пользователя
            var oidcUser = delegate.loadUser(userRequest)
            val accessToken = userRequest.accessToken
            val mappedAuthorities = HashSet<GrantedAuthority>()
            // TODO
            // 1) Осуществляем выборку информации о полномочиях из защищенного ресурса, используя accessToken
            // 2) Map the authority information на один или несколько GrantedAuthority и добавляем его в mappedAuthorities
            // 3) Создаем копию oidcUser, но используем mappedAuthorities
            oidcUser = DefaultOidcUser(mappedAuthorities, oidcUser.idToken, oidcUser.userInfo)
            oidcUser
        }
    }
}
Xml
<http>
	<oauth2-login oidc-user-service-ref="oidcUserService"
				  ...
    />
</http>

OAuth 2.0 UserService

DefaultOAuth2UserService – это реализация OAuth2UserService, которая поддерживает стандартных поставщиков OAuth 2.0.

OAuth2UserService получает пользовательские атрибуты конечного пользователя (владельца ресурса) из конечной точки UserInfo (используя токен доступа, предоставленный клиенту во время осуществления потока авторизации) и возвращает AuthenticatedPrincipal в форме OAuth2User.

DefaultOAuth2UserService использует RestOperations при запросе пользовательских атрибутов в конечной точке UserInfo.

Если необходимо настроить предварительную обработку запроса UserInfo, можно передать DefaultOAuth2UserService.setRequestEntityConverter() с кастомным Converter<OAuth2UserRequest, RequestEntity<?>>. Стандартная реализация OAuth2UserRequestEntityConverter строит представление RequestEntity запроса UserInfo, который по умолчанию устанавливает OAuth2AccessToken в заголовке Authorization.

С другой стороны, если нужно настроить пост-обработку ответа UserInfo, нужно будет передать DefaultOAuth2UserService.setRestOperations() с кастомно сконфигурированными RestOperations. RestOperations по умолчанию сконфигурированы следующим образом:

RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());

OAuth2ErrorResponseErrorHandler – это ResponseErrorHandler, который может обрабатывать ошибку OAuth 2.0 (400 Bad Request). Он использует OAuth2ErrorHttpMessageConverter для преобразования параметров ошибки OAuth 2.0 в OAuth2Error.

Независимо от того, настраиваете ли вы DefaultOAuth2UserService или передаете собственную реализацию OAuth2UserService, нужно будет сконфигурировать её, как показано в следующем примере:

Java
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {
	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			.oauth2Login(oauth2 -> oauth2
			    .userInfoEndpoint(userInfo -> userInfo
			        .userService(this.oauth2UserService())
			        ...
			    )
			);
		return http.build();
	}
	private OAuth2UserService<OAuth2UserRequest, OAuth2User> oauth2UserService() {
		...
	}
}
Kotlin
@EnableWebSecurity
class OAuth2LoginSecurityConfig {
    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            oauth2Login {
                userInfoEndpoint {
                    userService = oauth2UserService()
                    // ...
                }
            }
        }
        return http.build()
    }
    private fun oauth2UserService(): OAuth2UserService<OAuth2UserRequest, OAuth2User> {
        // ...
    }
}

OpenID Connect 1.0 UserService

OidcUserService – это реализация OAuth2UserService, которая поддерживает поставщика OpenID Connect 1.0.

OidcUserService использует DefaultOAuth2UserService при запросе пользовательских атрибутов в конечной точке UserInfo.

Если необходимо настроить предварительную обработку запроса UserInfo и/или последующую обработку ответа UserInfo, потребуется передать OidcUserService.setOauth2UserService() с кастомно сконфигурированной DefaultOAuth2UserService.

Независимо от того, настраиваете ли вы OidcUserService или передаете собственную реализацию OAuth2UserService для поставщика OpenID Connect 1.0, нужно будет сконфигурировать её, как показано в следующем примере:

Java
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {
	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			.oauth2Login(oauth2 -> oauth2
				.userInfoEndpoint(userInfo -> userInfo
				    .oidcUserService(this.oidcUserService())
				    ...
			    )
			);
		return http.build();
	}
	private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
		...
	}
}
Kotlin
@EnableWebSecurity
class OAuth2LoginSecurityConfig {
    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            oauth2Login {
                userInfoEndpoint {
                    oidcUserService = oidcUserService()
                    // ...
                }
            }
        }
        return http.build()
    }
    private fun oidcUserService(): OAuth2UserService<OidcUserRequest, OidcUser> {
        // ...
    }
}

Верификация сигнатуры ID токена

Аутентификация OpenID Connect 1.0 предусматривает ID токен, который является маркером безопасности, содержащим заявленные значения аутентификации конечного пользователя от сервера авторизации при использовании клиентом.

ID токен представлен в виде JSON веб-токена (JWT) и ДОЛЖЕН быть подписан с помощью JSON веб-сигнатуры (JWS).

OidcIdTokenDecoderFactory обеспечивает JwtDecoder, используемый для верификации сигнатуры OidcIdToken. Алгоритмом по умолчанию является RS256, но он может быть и другим, если назначить его при регистрации клиента. Для таких случаев распознаватель можно сконфигурировать на возврат ожидаемого алгоритма для JWS, назначенного для конкретного клиента.

Распознаватель алгоритмов для JWS - это Function, которая принимает ClientRegistration и возвращает ожидаемый JwsAlgorithm для клиента, например SignatureAlgorithm.RS256 или MacAlgorithm.HS256.

В следующем коде продемонстрировано, как сконфигурировать @Bean для OidcIdTokenDecoderFactory, который по умолчанию будет использовать MacAlgorithm.HS256 для всех ClientRegistration:

Java
@Bean
public JwtDecoderFactory<ClientRegistration> idTokenDecoderFactory() {
	OidcIdTokenDecoderFactory idTokenDecoderFactory = new OidcIdTokenDecoderFactory();
	idTokenDecoderFactory.setJwsAlgorithmResolver(clientRegistration -> MacAlgorithm.HS256);
	return idTokenDecoderFactory;
}
Kotlin
@Bean
fun idTokenDecoderFactory(): JwtDecoderFactory<ClientRegistration?> {
    val idTokenDecoderFactory = OidcIdTokenDecoderFactory()
    idTokenDecoderFactory.setJwsAlgorithmResolver { MacAlgorithm.HS256 }
    return idTokenDecoderFactory
}
Для алгоритмов на основе MAC, таких как HS256, HS384 или HS512, в качестве симметричного ключа для верификации подписи используется client-secret, соответствующий client-id.
Если для аутентификации в OpenID Connect 1.0 сконфигурировано более одной ClientRegistration, распознаватель алгоритмов для JWS может вычислить передаваемую ClientRegistration, чтобы определить, какой алгоритм возвращать.

Выход из системы OpenID Connect 1.0

OpenID Connect Session Management 1.0 предусматривает возможность регистрации выхода конечного пользователя из системы на стороне поставщика с помощью клиента. Одна из доступных стратегий – выход, инициированный клиентом (RP-Initiated Logout).

Если поставщик OpenID поддерживает как управление сессиями, так и обнаружение, клиент может получить URL-адрес конечной точки конечной точки end_session_endpoint из метаданных обнаружения поставщика OpenID. Это можно осуществить, сконфигурировав ClientRegistration с issuer-uri, как показано в следующем примере:

spring:
  security:
    oauth2:
      client:
        registration:
          okta:
            client-id: okta-client-id
            client-secret: okta-client-secret
            ...
        provider:
          okta:
            issuer-uri: https://dev-1234.oktapreview.com

…а OidcClientInitiatedLogoutSuccessHandler, который реализует инициируемый клиентом выход из системы, могут быть сконфигурированы следующим образом:

Java
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {
	@Autowired
	private ClientRegistrationRepository clientRegistrationRepository;
	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			.authorizeHttpRequests(authorize -> authorize
				.anyRequest().authenticated()
			)
			.oauth2Login(withDefaults())
			.logout(logout -> logout
				.logoutSuccessHandler(oidcLogoutSuccessHandler())
			);
		return http.build();
	}
	private LogoutSuccessHandler oidcLogoutSuccessHandler() {
		OidcClientInitiatedLogoutSuccessHandler oidcLogoutSuccessHandler =
				new OidcClientInitiatedLogoutSuccessHandler(this.clientRegistrationRepository);
		// Устанавливает местоположение, куда будет переадресован пользовательский агент конечного пользователя
		// после выхода из системы на стороне поставщика
		oidcLogoutSuccessHandler.setPostLogoutRedirectUri("{baseUrl}");
		return oidcLogoutSuccessHandler;
	}
}
Kotlin
@EnableWebSecurity
class OAuth2LoginSecurityConfig {
    @Autowired
    private lateinit var clientRegistrationRepository: ClientRegistrationRepository
    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            authorizeRequests {
                authorize(anyRequest, authenticated)
            }
            oauth2Login { }
            logout {
                logoutSuccessHandler = oidcLogoutSuccessHandler()
            }
        }
        return http.build()
    }
    private fun oidcLogoutSuccessHandler(): LogoutSuccessHandler {
        val oidcLogoutSuccessHandler = OidcClientInitiatedLogoutSuccessHandler(clientRegistrationRepository)
        // Устанавливает местоположение, куда будет переадресован пользовательский агент конечного пользователя
        // после выхода из системы на стороне поставщика
        oidcLogoutSuccessHandler.setPostLogoutRedirectUri("{baseUrl}")
        return oidcLogoutSuccessHandler
    }
}
OidcClientInitiatedLogoutSuccessHandler поддерживает плейсхолдер {baseUrl}. В случае использования основной URL-адрес приложения, например app.example.org, заменит его во время запроса.