Spring Authorization Server

默认情况下,Spring Authorization Server 中的动态客户端注册功能是禁用的。要启用此功能,请添加以下配置

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.security.config.annotation.web.builders.HttpSecurity;

import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;

import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;

import org.springframework.security.web.SecurityFilterChain;

import static sample.registration.CustomClientMetadataConfig.configureCustomClientMetadataConverters;

@Configuration

@EnableWebSecurity

public class SecurityConfig {

@Bean

public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {

OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =

OAuth2AuthorizationServerConfigurer.authorizationServer();

http

.securityMatcher(authorizationServerConfigurer.getEndpointsMatcher())

.with(authorizationServerConfigurer, (authorizationServer) ->

authorizationServer

.oidc((oidc) ->

oidc.clientRegistrationEndpoint((clientRegistrationEndpoint) -> (1)

clientRegistrationEndpoint

.authenticationProviders(configureCustomClientMetadataConverters()) (2)

)

)

)

.authorizeHttpRequests((authorize) ->

authorize

.anyRequest().authenticated()

);

return http.build();

}

}

1

使用默认配置启用 OpenID Connect 1.0 客户端注册端点。

2

可选地,自定义默认的 AuthenticationProvider 以支持自定义客户端元数据参数。

为了在注册客户端时支持自定义客户端元数据参数,还需要一些额外的实现细节。

以下示例展示了支持自定义客户端元数据参数(logo_uri 和 contacts)的 Converter 示例实现,这些参数在 OidcClientRegistrationAuthenticationProvider 和 OidcClientConfigurationAuthenticationProvider 中配置。

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import java.util.function.Consumer;

import java.util.function.Function;

import java.util.stream.Collectors;

import org.springframework.core.convert.converter.Converter;

import org.springframework.security.authentication.AuthenticationProvider;

import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;

import org.springframework.security.oauth2.server.authorization.oidc.OidcClientRegistration;

import org.springframework.security.oauth2.server.authorization.oidc.authentication.OidcClientConfigurationAuthenticationProvider;

import org.springframework.security.oauth2.server.authorization.oidc.authentication.OidcClientRegistrationAuthenticationProvider;

import org.springframework.security.oauth2.server.authorization.oidc.converter.OidcClientRegistrationRegisteredClientConverter;

import org.springframework.security.oauth2.server.authorization.oidc.converter.RegisteredClientOidcClientRegistrationConverter;

import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;

import org.springframework.util.CollectionUtils;

public class CustomClientMetadataConfig {

public static Consumer> configureCustomClientMetadataConverters() { (1)

List customClientMetadata = List.of("logo_uri", "contacts"); (2)

return (authenticationProviders) -> {

CustomRegisteredClientConverter registeredClientConverter =

new CustomRegisteredClientConverter(customClientMetadata);

CustomClientRegistrationConverter clientRegistrationConverter =

new CustomClientRegistrationConverter(customClientMetadata);

authenticationProviders.forEach((authenticationProvider) -> {

if (authenticationProvider instanceof OidcClientRegistrationAuthenticationProvider provider) {

provider.setRegisteredClientConverter(registeredClientConverter); (3)

provider.setClientRegistrationConverter(clientRegistrationConverter); (4)

}

if (authenticationProvider instanceof OidcClientConfigurationAuthenticationProvider provider) {

provider.setClientRegistrationConverter(clientRegistrationConverter); (5)

}

});

};

}

private static class CustomRegisteredClientConverter

implements Converter {

private final List customClientMetadata;

private final OidcClientRegistrationRegisteredClientConverter delegate;

private CustomRegisteredClientConverter(List customClientMetadata) {

this.customClientMetadata = customClientMetadata;

this.delegate = new OidcClientRegistrationRegisteredClientConverter();

}

@Override

public RegisteredClient convert(OidcClientRegistration clientRegistration) {

RegisteredClient registeredClient = this.delegate.convert(clientRegistration);

ClientSettings.Builder clientSettingsBuilder = ClientSettings.withSettings(

registeredClient.getClientSettings().getSettings());

if (!CollectionUtils.isEmpty(this.customClientMetadata)) {

clientRegistration.getClaims().forEach((claim, value) -> {

if (this.customClientMetadata.contains(claim)) {

clientSettingsBuilder.setting(claim, value);

}

});

}

return RegisteredClient.from(registeredClient)

.clientSettings(clientSettingsBuilder.build())

.build();

}

}

private static class CustomClientRegistrationConverter

implements Converter {

private final List customClientMetadata;

private final RegisteredClientOidcClientRegistrationConverter delegate;

private CustomClientRegistrationConverter(List customClientMetadata) {

this.customClientMetadata = customClientMetadata;

this.delegate = new RegisteredClientOidcClientRegistrationConverter();

}

@Override

public OidcClientRegistration convert(RegisteredClient registeredClient) {

OidcClientRegistration clientRegistration = this.delegate.convert(registeredClient);

Map claims = new HashMap<>(clientRegistration.getClaims());

if (!CollectionUtils.isEmpty(this.customClientMetadata)) {

ClientSettings clientSettings = registeredClient.getClientSettings();

claims.putAll(this.customClientMetadata.stream()

.filter(metadata -> clientSettings.getSetting(metadata) != null)

.collect(Collectors.toMap(Function.identity(), clientSettings::getSetting)));

}

return OidcClientRegistration.withClaims(claims).build();

}

}

}

1

定义一个 Consumer>,提供自定义默认 AuthenticationProvider 的能力。

2

定义客户端注册支持的自定义客户端元数据参数。

3

使用 CustomRegisteredClientConverter 配置 OidcClientRegistrationAuthenticationProvider.setRegisteredClientConverter()。

4

使用 CustomClientRegistrationConverter 配置 OidcClientRegistrationAuthenticationProvider.setClientRegistrationConverter()。

5

使用 CustomClientRegistrationConverter 配置 OidcClientConfigurationAuthenticationProvider.setClientRegistrationConverter()。