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 визначає href="https://openid.net/specs/openid-connect-core-1_0.html#UserInfo">кінцеву точку UserInfo наступним чином:

Кінцева точка UserInfo є захищеним ресурсом OAuth 2.0, який повертає дані про автентифікованого кінцевого користувача. Щоб отримати запитані дані про кінцевого користувача, клієнт запитує кінцеву точку UserInfo, використовуючи токен доступу, отриманий через автентифікацію OpenID Connect. Ці заявлені значення зазвичай представлені об'єктом JSON, який містить набір пар "ім'я-значення" для заявлених значень. 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-конфігурація.

У наступному коді показані всі параметри конфігурації, доступні в простір імен безпеки:

Параметри 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&&. Див. 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>

Кінцева точка переадресації

Кінцева точка переадресації використовується сервером авторизації для повернення відповіді авторизації (яка містить облікові дані авторизації) клієнту через користувацького агента власника ресурсу. Тому обліковими даними авторизації є код авторизації.

За замовчуванням відповідь на запит на авторизацію для 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) Здійснюємо вибірку інформації про повноваження із захищеного ресурсу, використовуючи accessToken
            // 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) Здійснюємо вибірку інформації про повноваження із захищеного ресурсу, використовуючи accessToken
            // 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, можна передати DefaultOAuth2UserServ з кастомним 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() з кастомно налаштованою DefaultOAuth2User.

Незалежно від того, чи ти налаштовуєш 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, заміни її під час запиту.