OAuth2
Spring Security は、包括的な OAuth 2.0 サポートを提供します。このセクションでは、OAuth 2.0 をサーブレットベースのアプリケーションに統合する方法について説明します。
概要
Spring Security の OAuth 2.0 サポートは、次の 2 つの主要な機能セットで構成されます。
OAuth2 ログインは非常に強力な OAuth2 クライアント機能であり、リファレンスドキュメントで独自のセクションを設ける価値があります。ただし、スタンドアロン機能としては存在せず、機能するには OAuth2 クライアントが必要です。 |
これらの機能セットは、OAuth 2.0 認証フレームワーク [IETF] (英語) で定義されたリソースサーバーロールとクライアントロールをカバーし、一方、認可サーバーロールは、Spring Security 上に構築された別個のプロジェクトである Spring Authorization Server によってカバーされます。
OAuth2 におけるリソースサーバーとクライアントのロールは、通常、1 つ以上のサーバー側アプリケーションによって表されます。さらに、認可サーバーのロールは、1 つ以上のサードパーティによって表すことができます (組織内で ID 管理や認証を集中管理する場合のように) - または - は、アプリケーションによって表すことができます (Spring Authorization Server の場合のように)。
例: 一般的な OAuth2 ベースのマイクロサービスアーキテクチャは、単一のユーザー向けクライアントアプリケーション、REST API を提供する複数のバックエンドリソースサーバー、およびユーザーと認証の問題を管理するためのサードパーティ認証サーバーで構成されます。また、これらのロールの 1 つだけを表す 1 つのアプリケーションがあり、他のロールを提供する 1 つ以上のサードパーティと統合する必要があることも一般的です。
Spring Security は、これらのシナリオなどを処理します。次のセクションでは、Spring Security によって提供されるロールについて説明し、一般的なシナリオの例を示します。
OAuth2 リソースサーバー
このセクションには、OAuth2 リソースサーバーの機能の概要と例が含まれています。完全なリファレンスドキュメントについては、OAuth 2.0 リソースサーバーを参照してください。 |
まず、spring-security-oauth2-resource-server
依存関係をプロジェクトに追加します。Spring Boot を使用する場合は、次のスターターを追加します。
Spring Boot を使用しない場合の追加オプションについては、Spring Security の入手を参照してください。 |
OAuth2 リソースサーバーの次の使用例を考慮してください。
OAuth2 を使用して API へのアクセスを保護したい (認可サーバーは JWT または不透明なアクセストークンを提供します)
JWT を使用して API へのアクセスを保護したい (カスタムトークン)
OAuth2 アクセストークンによるアクセスの保護
OAuth2 アクセストークンを使用して API へのアクセスを保護するのが非常に一般的です。ほとんどの場合、Spring Security では、OAuth2 でアプリケーションを保護するために最小限の構成のみが必要です。
Spring Security でサポートされる Bearer
トークンには 2 つの型があり、それぞれ検証に異なるコンポーネントを使用します。
JWT のサポートは
JwtDecoder
Bean を使用して署名を検証し、トークンをデコードしますOpaque トークンのサポートは
OpaqueTokenIntrospector
Bean を使用してトークンをイントロスペクトします
JWT のサポート
次の例では、Spring Boot 構成プロパティを使用して JwtDecoder
Bean を構成します。
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://my-auth-server.com
Spring Boot を使用する場合はこれだけで済みます。Spring Boot によって提供されるデフォルトの配置は次と同等です。
Java
Kotlin
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().authenticated()
)
.oauth2ResourceServer((oauth2) -> oauth2
.jwt(Customizer.withDefaults())
);
return http.build();
}
@Bean
public JwtDecoder jwtDecoder() {
return JwtDecoders.fromIssuerLocation("https://my-auth-server.com");
}
}
import org.springframework.security.config.annotation.web.invoke
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http {
authorizeHttpRequests {
authorize(anyRequest, authenticated)
}
oauth2ResourceServer {
jwt { }
}
}
return http.build()
}
@Bean
fun jwtDecoder(): JwtDecoder {
return JwtDecoders.fromIssuerLocation("https://my-auth-server.com")
}
}
Opaque トークンのサポート
次の例では、Spring Boot 構成プロパティを使用して OpaqueTokenIntrospector
Bean を構成します。
spring:
security:
oauth2:
resourceserver:
opaquetoken:
introspection-uri: https://my-auth-server.com/oauth2/introspect
client-id: my-client-id
client-secret: my-client-secret
Spring Boot を使用する場合はこれだけで済みます。Spring Boot によって提供されるデフォルトの配置は次と同等です。
Java
Kotlin
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().authenticated()
)
.oauth2ResourceServer((oauth2) -> oauth2
.opaqueToken(Customizer.withDefaults())
);
return http.build();
}
@Bean
public OpaqueTokenIntrospector opaqueTokenIntrospector() {
return new SpringOpaqueTokenIntrospector(
"https://my-auth-server.com/oauth2/introspect", "my-client-id", "my-client-secret");
}
}
import org.springframework.security.config.annotation.web.invoke
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http {
authorizeHttpRequests {
authorize(anyRequest, authenticated)
}
oauth2ResourceServer {
opaqueToken { }
}
}
return http.build()
}
@Bean
fun opaqueTokenIntrospector(): OpaqueTokenIntrospector {
return SpringOpaqueTokenIntrospector(
"https://my-auth-server.com/oauth2/introspect", "my-client-id", "my-client-secret"
)
}
}
カスタム JWT でアクセスを保護する
特にフロントエンドがシングルページアプリケーションとして開発されている場合、JWT を使用して API へのアクセスを保護することは、かなり一般的なゴールです。Spring Security の OAuth2 リソースサーバーサポートは、カスタム JWT を含むあらゆる型の Bearer
トークンに使用できます。
JWT を使用して API を保護するために必要なのは、署名の検証とトークンのデコードに使用される JwtDecoder
Bean だけです。Spring Security は、提供された Bean を自動的に使用して、SecurityFilterChain
内で保護を構成します。
次の例では、Spring Boot 構成プロパティを使用して JwtDecoder
Bean を構成します。
spring:
security:
oauth2:
resourceserver:
jwt:
public-key-location: classpath:my-public-key.pub
公開鍵をクラスパスリソース (この例では |
Spring Boot を使用する場合はこれだけで済みます。Spring Boot によって提供されるデフォルトの配置は次と同等です。
Java
Kotlin
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().authenticated()
)
.oauth2ResourceServer((oauth2) -> oauth2
.jwt(Customizer.withDefaults())
);
return http.build();
}
@Bean
public JwtDecoder jwtDecoder() {
return NimbusJwtDecoder.withPublicKey(publicKey()).build();
}
private RSAPublicKey publicKey() {
// ...
}
}
import org.springframework.security.config.annotation.web.invoke
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http {
authorizeHttpRequests {
authorize(anyRequest, authenticated)
}
oauth2ResourceServer {
jwt { }
}
}
return http.build()
}
@Bean
fun jwtDecoder(): JwtDecoder {
return NimbusJwtDecoder.withPublicKey(publicKey()).build()
}
private fun publicKey(): RSAPublicKey {
// ...
}
}
Spring Security は、トークンを鋳造するためのエンドポイントを提供しません。ただし、Spring Security は、 |
OAuth2 クライアント
このセクションには、OAuth2 クライアントの機能の概要と例が含まれています。完全なリファレンスドキュメントについては、OAuth 2.0 クライアントおよび OAuth 2.0 ログインを参照してください。 |
まず、spring-security-oauth2-client
依存関係をプロジェクトに追加します。Spring Boot を使用する場合は、次のスターターを追加します。
Gradle
Maven
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
Spring Boot を使用しない場合の追加オプションについては、Spring Security の入手を参照してください。 |
OAuth2 クライアントの次の使用例を考慮してください。
サードパーティの API にアクセスするために、
RestClient
を使用してユーザーのアクセストークンを取得したいサードパーティの API にアクセスするために、
WebClient
を使用してユーザーのアクセストークンを取得したい両方やりたい (ユーザーをログインさせてサードパーティ API にアクセスする)
client_credentials
付与型を使用して、アプリケーションごとに 1 つのトークンを取得したい
OAuth2 を使用してユーザーをログインする
ユーザーに OAuth2 経由でのログインを要求するのは非常に一般的です。OpenID Connect 1.0 (英語) は、id_token
と呼ばれる特別なトークンを提供します。これは、OAuth2 クライアントにユーザー ID 検証を実行し、ユーザーにログインする機能を提供するように設計されています。場合によっては、OAuth2 を直接使用してユーザーをログインできます (一般的なソーシャルアプリケーションの場合と同様)。GitHub や Facebook など、OpenID Connect を実装していないログインプロバイダー)。
次の例では、OAuth2 または OpenID Connect を使用してユーザーをログインできる OAuth2 クライアントとして機能するようにアプリケーションを構成します。
Java
Kotlin
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// ...
.oauth2Login(Customizer.withDefaults());
return http.build();
}
}
import org.springframework.security.config.annotation.web.invoke
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http {
// ...
oauth2Login { }
}
return http.build()
}
}
上記の構成に加えて、アプリケーションでは、ClientRegistrationRepository
Bean を使用して少なくとも 1 つの ClientRegistration
を構成する必要があります。次の例では、Spring Boot 構成プロパティを使用して InMemoryClientRegistrationRepository
Bean を構成します。
spring:
security:
oauth2:
client:
registration:
my-oidc-client:
provider: my-oidc-provider
client-id: my-client-id
client-secret: my-client-secret
authorization-grant-type: authorization_code
scope: openid,profile
provider:
my-oidc-provider:
issuer-uri: https://my-oidc-provider.com
上記の構成により、アプリケーションは 2 つの追加エンドポイントをサポートするようになりました。
ログインエンドポイント (例:
/oauth2/authorization/my-oidc-client
) は、ログインを開始し、サードパーティの認可サーバーへのリダイレクトを実行するために使用されます。リダイレクトエンドポイント (例:
/login/oauth2/code/my-oidc-client
) は、クライアントアプリケーションにリダイレクトするために認可サーバーによって使用され、アクセストークンリクエストを通じてid_token
および / またはaccess_token
を取得するために使用されるcode
パラメーターが含まれます。
上記の構成に |
保護されたリソースへのアクセス
OAuth2 によって保護されているサードパーティ API にリクエストを行うことは、OAuth2 クライアントの中心的な使用例です。これは、クライアント (Spring Security の OAuth2AuthorizedClient
クラスで表される) を承認し、発信リクエストの Authorization
ヘッダーに Bearer
トークンを配置して保護されたリソースにアクセスすることによって実現されます。
次の例では、サードパーティ API から保護されたリソースをリクエストできる OAuth2 クライアントとして機能するようにアプリケーションを構成します。
Java
Kotlin
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// ...
.oauth2Client(Customizer.withDefaults());
return http.build();
}
}
import org.springframework.security.config.annotation.web.invoke
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http {
// ...
oauth2Client { }
}
return http.build()
}
}
上の例では、ユーザーをログインする方法が提供されていません。他のログインメカニズム ( |
上記の構成に加えて、アプリケーションでは、ClientRegistrationRepository
Bean を使用して少なくとも 1 つの ClientRegistration
を構成する必要があります。次の例では、Spring Boot 構成プロパティを使用して InMemoryClientRegistrationRepository
Bean を構成します。
spring:
security:
oauth2:
client:
registration:
my-oauth2-client:
provider: my-auth-server
client-id: my-client-id
client-secret: my-client-secret
authorization-grant-type: authorization_code
scope: message.read,message.write
provider:
my-auth-server:
issuer-uri: https://my-auth-server.com
OAuth2 クライアント機能をサポートするように Spring Security を構成することに加えて、保護されたリソースにアクセスする方法を決定し、それに応じてアプリケーションを構成する必要もあります。Spring Security は、保護されたリソースへのアクセスに使用できるアクセストークンを取得するための OAuth2AuthorizedClientManager
の実装を提供します。
Spring Security は、デフォルトの |
OAuth2AuthorizedClientManager
を使用する最も簡単な方法は、spring-web
がクラスパス上にある場合にすでに使用可能な RestClient
を介してリクエストをインターセプトする ClientHttpRequestInterceptor
を使用することです。
次の例では、デフォルトの OAuth2AuthorizedClientManager
を使用して、各リクエストの Authorization
ヘッダーに Bearer
トークンを配置することで、保護されたリソースにアクセスできる RestClient
を構成します。
ClientHttpRequestInterceptor
を使用して RestClient
を構成する Java
Kotlin
@Configuration
public class RestClientConfig {
@Bean
public RestClient restClient(OAuth2AuthorizedClientManager authorizedClientManager) {
OAuth2ClientHttpRequestInterceptor requestInterceptor =
new OAuth2ClientHttpRequestInterceptor(authorizedClientManager);
return RestClient.builder()
.requestInterceptor(requestInterceptor)
.build();
}
}
@Configuration
class RestClientConfig {
@Bean
fun restClient(authorizedClientManager: OAuth2AuthorizedClientManager): RestClient {
val requestInterceptor = OAuth2ClientHttpRequestInterceptor(authorizedClientManager)
return RestClient.builder()
.requestInterceptor(requestInterceptor)
.build()
}
}
この構成された RestClient
は、次の例のように使用できます。
RestClient
を使用して保護されたリソースにアクセスする Java
Kotlin
import static org.springframework.security.oauth2.client.web.client.RequestAttributeClientRegistrationIdResolver.clientRegistrationId;
@RestController
public class MessagesController {
private final RestClient restClient;
public MessagesController(RestClient restClient) {
this.restClient = restClient;
}
@GetMapping("/messages")
public ResponseEntity<List<Message>> messages() {
Message[] messages = this.restClient.get()
.uri("http://localhost:8090/messages")
.attributes(clientRegistrationId("my-oauth2-client"))
.retrieve()
.body(Message[].class);
return ResponseEntity.ok(Arrays.asList(messages));
}
public record Message(String message) {
}
}
import org.springframework.security.oauth2.client.web.client.RequestAttributeClientRegistrationIdResolver.clientRegistrationId
import org.springframework.web.client.body
@RestController
class MessagesController(private val restClient: RestClient) {
@GetMapping("/messages")
fun messages(): ResponseEntity<List<Message>> {
val messages = restClient.get()
.uri("http://localhost:8090/messages")
.attributes(clientRegistrationId("my-oauth2-client"))
.retrieve()
.body<Array<Message>>()!!
.toList()
return ResponseEntity.ok(messages)
}
data class Message(val message: String)
}
WebClient
で保護されたリソースにアクセスする
OAuth2 によって保護されているサードパーティ API にリクエストを行うことは、OAuth2 クライアントの中心的な使用例です。これは、クライアント (Spring Security の OAuth2AuthorizedClient
クラスで表される) を承認し、発信リクエストの Authorization
ヘッダーに Bearer
トークンを配置して保護されたリソースにアクセスすることによって実現されます。
次の例では、サードパーティ API から保護されたリソースをリクエストできる OAuth2 クライアントとして機能するようにアプリケーションを構成します。
Java
Kotlin
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// ...
.oauth2Client(Customizer.withDefaults());
return http.build();
}
}
import org.springframework.security.config.annotation.web.invoke
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http {
// ...
oauth2Client { }
}
return http.build()
}
}
上記の例では、ユーザーをログインする方法は提供されていません。他のログインメカニズム ( |
上記の構成に加えて、アプリケーションでは、ClientRegistrationRepository
Bean を使用して少なくとも 1 つの ClientRegistration
を構成する必要があります。次の例では、Spring Boot 構成プロパティを使用して InMemoryClientRegistrationRepository
Bean を構成します。
spring:
security:
oauth2:
client:
registration:
my-oauth2-client:
provider: my-auth-server
client-id: my-client-id
client-secret: my-client-secret
authorization-grant-type: authorization_code
scope: message.read,message.write
provider:
my-auth-server:
issuer-uri: https://my-auth-server.com
OAuth2 クライアント機能をサポートするように Spring Security を構成することに加えて、保護されたリソースにアクセスする方法を決定し、それに応じてアプリケーションを構成する必要もあります。Spring Security は、保護されたリソースへのアクセスに使用できるアクセストークンを取得するための OAuth2AuthorizedClientManager
の実装を提供します。
Spring Security は、デフォルトの |
RestClient
を構成する代わりに、OAuth2AuthorizedClientManager
を使用する別の方法は、WebClient
を介してリクエストをインターセプトする ExchangeFilterFunction
を使用することです。WebClient
を使用するには、リアクティブクライアント実装とともに spring-webflux
依存関係を追加する必要があります。
Gradle
Maven
implementation 'org.springframework:spring-webflux'
implementation 'io.projectreactor.netty:reactor-netty'
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor.netty</groupId>
<artifactId>reactor-netty</artifactId>
</dependency>
次の例では、デフォルトの OAuth2AuthorizedClientManager
を使用して、各リクエストの Authorization
ヘッダーに Bearer
トークンを配置することで、保護されたリソースにアクセスできる WebClient
を構成します。
ExchangeFilterFunction
を使用して WebClient
を構成する Java
Kotlin
@Configuration
public class WebClientConfig {
@Bean
public WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {
ServletOAuth2AuthorizedClientExchangeFilterFunction filter =
new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
return WebClient.builder()
.apply(filter.oauth2Configuration())
.build();
}
}
@Configuration
class WebClientConfig {
@Bean
fun webClient(authorizedClientManager: OAuth2AuthorizedClientManager): WebClient {
val filter = ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager)
return WebClient.builder()
.apply(filter.oauth2Configuration())
.build()
}
}
この構成された WebClient
は、次の例のように使用できます。
WebClient
を使用して保護されたリソースにアクセスする Java
Kotlin
import static org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId;
@RestController
public class MessagesController {
private final WebClient webClient;
public MessagesController(WebClient webClient) {
this.webClient = webClient;
}
@GetMapping("/messages")
public ResponseEntity<List<Message>> messages() {
return this.webClient.get()
.uri("http://localhost:8090/messages")
.attributes(clientRegistrationId("my-oauth2-client"))
.retrieve()
.toEntityList(Message.class)
.block();
}
public record Message(String message) {
}
}
import org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId
@RestController
class MessagesController(private val webClient: WebClient) {
@GetMapping("/messages")
fun messages(): ResponseEntity<List<Message>> {
return webClient.get()
.uri("http://localhost:8090/messages")
.attributes(clientRegistrationId("my-oauth2-client"))
.retrieve()
.toEntityList<Message>()
.block()!!
}
data class Message(val message: String)
}
現在のユーザーの保護されたリソースへのアクセス
ユーザーが OAuth2 または OpenID Connect 経由でログインすると、認可サーバーは、保護されたリソースに直接アクセスするために使用できるアクセストークンを提供する場合があります。これは、単一の ClientRegistration
を両方の使用例に対して同時に構成するだけで済むため、便利です。
このセクションでは、OAuth2 を使用してユーザーをログインすると保護されたリソースへのアクセスを単一の構成に結合します。ログイン用に 1 つの |
次の例では、ユーザーをログインさせ、サードパーティ API から保護されたリソースをリクエストできる OAuth2 クライアントとして機能するようにアプリケーションを構成します。
Java
Kotlin
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// ...
.oauth2Login(Customizer.withDefaults())
.oauth2Client(Customizer.withDefaults());
return http.build();
}
}
import org.springframework.security.config.annotation.web.invoke
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http {
// ...
oauth2Login { }
oauth2Client { }
}
return http.build()
}
}
上記の構成に加えて、アプリケーションでは、ClientRegistrationRepository
Bean を使用して少なくとも 1 つの ClientRegistration
を構成する必要があります。次の例では、Spring Boot 構成プロパティを使用して InMemoryClientRegistrationRepository
Bean を構成します。
spring:
security:
oauth2:
client:
registration:
my-combined-client:
provider: my-auth-server
client-id: my-client-id
client-secret: my-client-secret
authorization-grant-type: authorization_code
scope: openid,profile,message.read,message.write
provider:
my-auth-server:
issuer-uri: https://my-auth-server.com
前の例 ( OAuth2 を使用してユーザーをログインする、保護されたリソースへのアクセス ) とこの例の主な違いは、標準スコープ |
OAuth2 クライアント機能をサポートするように Spring Security を構成することに加えて、保護されたリソースにアクセスする方法を決定し、それに応じてアプリケーションを構成する必要もあります。Spring Security は、保護されたリソースへのアクセスに使用できるアクセストークンを取得するための OAuth2AuthorizedClientManager
の実装を提供します。
Spring Security は、デフォルトの |
OAuth2AuthorizedClientManager
を使用する最も簡単な方法は、spring-web
がクラスパス上にある場合にすでに使用可能な RestClient
を介してリクエストをインターセプトする ClientHttpRequestInterceptor
を使用することです。
次の例では、デフォルトの OAuth2AuthorizedClientManager
を使用して、各リクエストの Authorization
ヘッダーに Bearer
トークンを配置することで、保護されたリソースにアクセスできる RestClient
を構成します。
ClientHttpRequestInterceptor
を使用して RestClient
を構成する Java
Kotlin
@Configuration
public class RestClientConfig {
@Bean
public RestClient restClient(OAuth2AuthorizedClientManager authorizedClientManager) {
OAuth2ClientHttpRequestInterceptor requestInterceptor =
new OAuth2ClientHttpRequestInterceptor(authorizedClientManager);
requestInterceptor.setClientRegistrationIdResolver(clientRegistrationIdResolver());
return RestClient.builder()
.requestInterceptor(requestInterceptor)
.build();
}
private static ClientRegistrationIdResolver clientRegistrationIdResolver() {
return (request) -> {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return (authentication instanceof OAuth2AuthenticationToken principal)
? principal.getAuthorizedClientRegistrationId()
: null;
};
}
}
@Configuration
class RestClientConfig {
@Bean
fun restClient(authorizedClientManager: OAuth2AuthorizedClientManager): RestClient {
val requestInterceptor = OAuth2ClientHttpRequestInterceptor(authorizedClientManager)
requestInterceptor.setClientRegistrationIdResolver(clientRegistrationIdResolver())
return RestClient.builder()
.requestInterceptor(requestInterceptor)
.build()
}
private fun clientRegistrationIdResolver(): OAuth2ClientHttpRequestInterceptor.ClientRegistrationIdResolver {
return OAuth2ClientHttpRequestInterceptor.ClientRegistrationIdResolver { request ->
val authentication = SecurityContextHolder.getContext().authentication
if (authentication is OAuth2AuthenticationToken) {
authentication.authorizedClientRegistrationId
} else {
null
}
}
}
}
この構成された RestClient
は、次の例のように使用できます。
RestClient
を使用して保護されたリソースにアクセスする (現行ユーザー)Java
Kotlin
@RestController
public class MessagesController {
private final RestClient restClient;
public MessagesController(RestClient restClient) {
this.restClient = restClient;
}
@GetMapping("/messages")
public ResponseEntity<List<Message>> messages() {
Message[] messages = this.restClient.get()
.uri("http://localhost:8090/messages")
.retrieve()
.body(Message[].class);
return ResponseEntity.ok(Arrays.asList(messages));
}
public record Message(String message) {
}
}
import org.springframework.web.client.body
@RestController
class MessagesController(private val restClient: RestClient) {
@GetMapping("/messages")
fun messages(): ResponseEntity<List<Message>> {
val messages = restClient.get()
.uri("http://localhost:8090/messages")
.retrieve()
.body<Array<Message>>()!!
.toList()
return ResponseEntity.ok(messages)
}
data class Message(val message: String)
}
前の例とは異なり、使用したい |
クライアント資格情報付与を使用する
このセクションでは、クライアント資格情報付与型に関する追加の考慮事項に焦点を当てます。すべての付与型での一般的な設定と使用方法については、保護されたリソースへのアクセスを参照してください。 |
クライアント資格情報の付与 [IETF] (英語) により、クライアントは自身に代わって access_token
を取得できます。クライアント資格情報の付与は、リソース所有者 (つまり、ユーザー) が関与しない単純なフローです。
クライアント資格情報の付与の一般的な使用箇所は、あらゆるリクエスト (またはユーザー) がアクセストークンを取得し、リソースサーバーに保護されたリソースリクエストを行うことができる可能性があることに注意することが重要です。すべてのリクエストがアクセストークンを取得できるため、ユーザーが不正なリクエストを行えないように、アプリケーションを設計する際には注意してください。 |
ユーザーがログインできる Web アプリケーション内でアクセストークンを取得する場合、Spring Security のデフォルトの動作では、ユーザーごとにアクセストークンを取得します。
デフォルトでは、アクセストークンのスコープは現在のユーザーのプリンシパル名に設定されており、すべてのユーザーが一意のアクセストークンを受け取ることになります。 |
クライアント資格情報付与を使用するクライアントでは、通常、アクセストークンのスコープを個々のユーザーではなくアプリケーションに設定する必要があるため、アプリケーションごとにアクセストークンは 1 つだけになります。アクセストークンのスコープをアプリケーションに設定するには、カスタムプリンシパル名を解決するための戦略を設定する必要があります。次の例では、RequestAttributePrincipalResolver
を使用して RestClient
を構成することでこれを実行します。
client_credentials
用に RestClient
を構成する Java
Kotlin
@Configuration
public class RestClientConfig {
@Bean
public RestClient restClient(OAuth2AuthorizedClientManager authorizedClientManager) {
OAuth2ClientHttpRequestInterceptor requestInterceptor =
new OAuth2ClientHttpRequestInterceptor(authorizedClientManager);
requestInterceptor.setPrincipalResolver(new RequestAttributePrincipalResolver());
return RestClient.builder()
.requestInterceptor(requestInterceptor)
.build();
}
}
@Configuration
class RestClientConfig {
@Bean
fun restClient(authorizedClientManager: OAuth2AuthorizedClientManager): RestClient {
val requestInterceptor = OAuth2ClientHttpRequestInterceptor(authorizedClientManager)
requestInterceptor.setPrincipalResolver(RequestAttributePrincipalResolver())
return RestClient.builder()
.requestInterceptor(requestInterceptor)
.build()
}
}
上記の構成では、各リクエストにプリンシパル名を指定できます。次の例は、プリンシパル名を指定してアクセストークンのスコープをアプリケーションに設定する方法を示しています。
Java
Kotlin
import static org.springframework.security.oauth2.client.web.client.RequestAttributeClientRegistrationIdResolver.clientRegistrationId;
import static org.springframework.security.oauth2.client.web.client.RequestAttributePrincipalResolver.principal;
@RestController
public class MessagesController {
private final RestClient restClient;
public MessagesController(RestClient restClient) {
this.restClient = restClient;
}
@GetMapping("/messages")
public ResponseEntity<List<Message>> messages() {
Message[] messages = this.restClient.get()
.uri("http://localhost:8090/messages")
.attributes(clientRegistrationId("my-oauth2-client"))
.attributes(principal("my-application"))
.retrieve()
.body(Message[].class);
return ResponseEntity.ok(Arrays.asList(messages));
}
public record Message(String message) {
}
}
import org.springframework.security.oauth2.client.web.client.RequestAttributeClientRegistrationIdResolver.clientRegistrationId
import org.springframework.security.oauth2.client.web.client.RequestAttributePrincipalResolver.principal
import org.springframework.web.client.body
@RestController
class MessagesController(private val restClient: RestClient) {
@GetMapping("/messages")
fun messages(): ResponseEntity<List<Message>> {
val messages = restClient.get()
.uri("http://localhost:8090/messages")
.attributes(clientRegistrationId("my-oauth2-client"))
.attributes(principal("my-application"))
.retrieve()
.body<Array<Message>>()!!
.toList()
return ResponseEntity.ok(messages)
}
data class Message(val message: String)
}
上記の例のように属性を介してプリンシパル名を指定すると、アクセストークンは 1 つだけになり、すべてのリクエストに使用されます。 |
拡張許可型を有効にする
一般的な使用例では、拡張付与型の有効化や構成が行われます。例: Spring Security は jwt-bearer
および token-exchange
付与型のサポートを提供しますが、これらはコア OAuth 2.0 仕様の一部ではないため、デフォルトでは有効になりません。
Spring Security 6.2 以降では、1 つ以上の OAuth2AuthorizedClientProvider
に対して Bean を発行するだけで、自動的に取得されます。次の例では、単純に jwt-bearer
許可型を有効にします。
jwt-bearer
許可型を有効にする Java
Kotlin
@Configuration
public class SecurityConfig {
@Bean
public OAuth2AuthorizedClientProvider jwtBearer() {
return new JwtBearerOAuth2AuthorizedClientProvider();
}
}
@Configuration
class SecurityConfig {
@Bean
fun jwtBearer(): OAuth2AuthorizedClientProvider {
return JwtBearerOAuth2AuthorizedClientProvider()
}
}
デフォルトの OAuth2AuthorizedClientManager
がまだ提供されていない場合は、Spring Security によって自動的に発行されます。
カスタム |
Spring Security 6.2 より前に上記の構成を実現するには、この Bean を自分で公開し、デフォルトの許可型も再度有効にする必要がありました。バックグラウンドで何が構成されているかを理解するために、構成は次のようになります。
jwt-bearer
許可型を有効にする (6.2 より前)Java
Kotlin
@Configuration
public class SecurityConfig {
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.authorizationCode()
.refreshToken()
.clientCredentials()
.password()
.provider(new JwtBearerOAuth2AuthorizedClientProvider())
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
}
@Configuration
class SecurityConfig {
@Bean
fun authorizedClientManager(
clientRegistrationRepository: ClientRegistrationRepository,
authorizedClientRepository: OAuth2AuthorizedClientRepository
): OAuth2AuthorizedClientManager {
val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
.authorizationCode()
.refreshToken()
.clientCredentials()
.password()
.provider(JwtBearerOAuth2AuthorizedClientProvider())
.build()
val authorizedClientManager = DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository
)
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
return authorizedClientManager
}
}
既存の権限付与型をカスタマイズする
Bean を公開して拡張付与型を有効にできる機能により、デフォルトを再定義することなく、既存の付与型をカスタマイズする機会も提供されます。例: client_credentials
許可のために OAuth2AuthorizedClientProvider
のクロックスキューをカスタマイズしたい場合は、次のように Bean を発行するだけです。
Java
Kotlin
@Configuration
public class SecurityConfig {
@Bean
public OAuth2AuthorizedClientProvider clientCredentials() {
ClientCredentialsOAuth2AuthorizedClientProvider authorizedClientProvider =
new ClientCredentialsOAuth2AuthorizedClientProvider();
authorizedClientProvider.setClockSkew(Duration.ofMinutes(5));
return authorizedClientProvider;
}
}
@Configuration
class SecurityConfig {
@Bean
fun clientCredentials(): OAuth2AuthorizedClientProvider {
val authorizedClientProvider = ClientCredentialsOAuth2AuthorizedClientProvider()
authorizedClientProvider.setClockSkew(Duration.ofMinutes(5))
return authorizedClientProvider
}
}
トークンリクエストパラメーターのカスタマイズ
アクセストークンを取得するときにリクエストパラメーターをカスタマイズする必要があることは、非常に一般的です。例: プロバイダーが authorization_code
許可にこのパラメーターを必要とするため、カスタム audience
パラメーターをトークンリクエストに追加するとします。
Spring Security 6.2 以降では、型 OAuth2AccessTokenResponseClient
の Bean をジェネリクス型 OAuth2AuthorizationCodeGrantRequest
で発行するだけで、Spring Security がそれを使用して OAuth2 クライアントコンポーネントを構成できます。
次の例では、DSL を使用せずに authorization_code
許可のトークンリクエストパラメーターをカスタマイズします。
Java
Kotlin
@Configuration
public class SecurityConfig {
@Bean
public OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> authorizationCodeAccessTokenResponseClient() {
OAuth2AuthorizationCodeGrantRequestEntityConverter requestEntityConverter =
new OAuth2AuthorizationCodeGrantRequestEntityConverter();
requestEntityConverter.addParametersConverter(parametersConverter());
DefaultAuthorizationCodeTokenResponseClient accessTokenResponseClient =
new DefaultAuthorizationCodeTokenResponseClient();
accessTokenResponseClient.setRequestEntityConverter(requestEntityConverter);
return accessTokenResponseClient;
}
private static Converter<OAuth2AuthorizationCodeGrantRequest, MultiValueMap<String, String>> parametersConverter() {
return (grantRequest) -> {
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
parameters.set("audience", "xyz_value");
return parameters;
};
}
}
@Configuration
class SecurityConfig {
@Bean
fun authorizationCodeAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> {
val requestEntityConverter = OAuth2AuthorizationCodeGrantRequestEntityConverter()
requestEntityConverter.addParametersConverter(parametersConverter())
val accessTokenResponseClient = DefaultAuthorizationCodeTokenResponseClient()
accessTokenResponseClient.setRequestEntityConverter(requestEntityConverter)
return accessTokenResponseClient
}
private fun parametersConverter(): Converter<OAuth2AuthorizationCodeGrantRequest, MultiValueMap<String, String>> {
return Converter<OAuth2AuthorizationCodeGrantRequest, MultiValueMap<String, String>> { grantRequest ->
LinkedMultiValueMap<String, String>().also { parameters ->
parameters["audience"] = "xyz_value"
}
}
}
}
この場合、 |
Spring Security 6.2 より前は、Spring Security DSL を使用して、このカスタマイズが OAuth2 ログイン (この機能を使用している場合) と OAuth2 クライアントコンポーネントの両方に適用されていることを確認する必要がありました。バックグラウンドで何が構成されているかを理解するために、構成は次のようになります。
Java
Kotlin
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationCodeGrantRequestEntityConverter requestEntityConverter =
new OAuth2AuthorizationCodeGrantRequestEntityConverter();
requestEntityConverter.addParametersConverter(parametersConverter());
DefaultAuthorizationCodeTokenResponseClient accessTokenResponseClient =
new DefaultAuthorizationCodeTokenResponseClient();
accessTokenResponseClient.setRequestEntityConverter(requestEntityConverter);
http
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().authenticated()
)
.oauth2Login((oauth2Login) -> oauth2Login
.tokenEndpoint((tokenEndpoint) -> tokenEndpoint
.accessTokenResponseClient(accessTokenResponseClient)
)
)
.oauth2Client((oauth2Client) -> oauth2Client
.authorizationCodeGrant((authorizationCode) -> authorizationCode
.accessTokenResponseClient(accessTokenResponseClient)
)
);
return http.build();
}
private static Converter<OAuth2AuthorizationCodeGrantRequest, MultiValueMap<String, String>> parametersConverter() {
// ...
}
}
import org.springframework.security.config.annotation.web.invoke
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
val requestEntityConverter = OAuth2AuthorizationCodeGrantRequestEntityConverter()
requestEntityConverter.addParametersConverter(parametersConverter())
val tokenResponseClient = DefaultAuthorizationCodeTokenResponseClient()
tokenResponseClient.setRequestEntityConverter(requestEntityConverter)
http {
authorizeHttpRequests {
authorize(anyRequest, authenticated)
}
oauth2Login {
tokenEndpoint {
accessTokenResponseClient = tokenResponseClient
}
}
oauth2Client {
authorizationCodeGrant {
accessTokenResponseClient = tokenResponseClient
}
}
}
return http.build()
}
private fun parametersConverter(): Converter<OAuth2AuthorizationCodeGrantRequest, MultiValueMap<String, String>> {
// ...
}
}
他の許可型の場合は、追加の OAuth2AccessTokenResponseClient
Bean を公開してデフォルトをオーバーライドできます。例: client_credentials
付与のトークンリクエストをカスタマイズするには、次の Bean を発行します。
Java
Kotlin
@Configuration
public class SecurityConfig {
@Bean
public OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> clientCredentialsAccessTokenResponseClient() {
OAuth2ClientCredentialsGrantRequestEntityConverter requestEntityConverter =
new OAuth2ClientCredentialsGrantRequestEntityConverter();
requestEntityConverter.addParametersConverter(parametersConverter());
DefaultClientCredentialsTokenResponseClient accessTokenResponseClient =
new DefaultClientCredentialsTokenResponseClient();
accessTokenResponseClient.setRequestEntityConverter(requestEntityConverter);
return accessTokenResponseClient;
}
private static Converter<OAuth2ClientCredentialsGrantRequest, MultiValueMap<String, String>> parametersConverter() {
// ...
}
}
@Configuration
class SecurityConfig {
@Bean
fun clientCredentialsAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> {
val requestEntityConverter = OAuth2ClientCredentialsGrantRequestEntityConverter()
requestEntityConverter.addParametersConverter(parametersConverter())
val accessTokenResponseClient = DefaultClientCredentialsTokenResponseClient()
accessTokenResponseClient.setRequestEntityConverter(requestEntityConverter)
return accessTokenResponseClient
}
private fun parametersConverter(): Converter<OAuth2ClientCredentialsGrantRequest, MultiValueMap<String, String>> {
// ...
}
}
Spring Security は、次の汎用型の OAuth2AccessTokenResponseClient
Bean を自動的に解決します。
OAuth2AuthorizationCodeGrantRequest
(DefaultAuthorizationCodeTokenResponseClient
を参照)OAuth2RefreshTokenGrantRequest
(DefaultRefreshTokenTokenResponseClient
を参照)OAuth2ClientCredentialsGrantRequest
(DefaultClientCredentialsTokenResponseClient
を参照)OAuth2PasswordGrantRequest
(DefaultPasswordTokenResponseClient
を参照)JwtBearerGrantRequest
(DefaultJwtBearerTokenResponseClient
を参照)TokenExchangeGrantRequest
(DefaultTokenExchangeTokenResponseClient
を参照)
型 |
型 |
OAuth2 クライアントコンポーネントで使用される RestOperations
をカスタマイズする
もう 1 つの一般的な使用例は、アクセストークンを取得するときに使用される RestOperations
をカスタマイズする必要があることです。レスポンスの処理をカスタマイズするため (カスタム HttpMessageConverter
経由)、または企業ネットワークにプロキシ設定を適用するために (カスタマイズされた ClientHttpRequestFactory
経由)、これを行う必要がある場合があります。
Spring Security 6.2 以降では、型 OAuth2AccessTokenResponseClient
の Bean を発行するだけで、Spring Security が OAuth2AuthorizedClientManager
Bean を構成して発行します。
次の例では、サポートされているすべての許可型の RestOperations
をカスタマイズします。
RestOperations
をカスタマイズする Java
Kotlin
@Configuration
public class SecurityConfig {
@Bean
public OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> authorizationCodeAccessTokenResponseClient() {
DefaultAuthorizationCodeTokenResponseClient accessTokenResponseClient =
new DefaultAuthorizationCodeTokenResponseClient();
accessTokenResponseClient.setRestOperations(restTemplate());
return accessTokenResponseClient;
}
@Bean
public OAuth2AccessTokenResponseClient<OAuth2RefreshTokenGrantRequest> refreshTokenAccessTokenResponseClient() {
DefaultRefreshTokenTokenResponseClient accessTokenResponseClient =
new DefaultRefreshTokenTokenResponseClient();
accessTokenResponseClient.setRestOperations(restTemplate());
return accessTokenResponseClient;
}
@Bean
public OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> clientCredentialsAccessTokenResponseClient() {
DefaultClientCredentialsTokenResponseClient accessTokenResponseClient =
new DefaultClientCredentialsTokenResponseClient();
accessTokenResponseClient.setRestOperations(restTemplate());
return accessTokenResponseClient;
}
@Bean
public OAuth2AccessTokenResponseClient<OAuth2PasswordGrantRequest> passwordAccessTokenResponseClient() {
DefaultPasswordTokenResponseClient accessTokenResponseClient =
new DefaultPasswordTokenResponseClient();
accessTokenResponseClient.setRestOperations(restTemplate());
return accessTokenResponseClient;
}
@Bean
public OAuth2AccessTokenResponseClient<JwtBearerGrantRequest> jwtBearerAccessTokenResponseClient() {
DefaultJwtBearerTokenResponseClient accessTokenResponseClient =
new DefaultJwtBearerTokenResponseClient();
accessTokenResponseClient.setRestOperations(restTemplate());
return accessTokenResponseClient;
}
@Bean
public OAuth2AccessTokenResponseClient<TokenExchangeGrantRequest> tokenExchangeAccessTokenResponseClient() {
DefaultTokenExchangeTokenResponseClient accessTokenResponseClient =
new DefaultTokenExchangeTokenResponseClient();
accessTokenResponseClient.setRestOperations(restTemplate());
return accessTokenResponseClient;
}
@Bean
public RestTemplate restTemplate() {
// ...
}
}
@Configuration
class SecurityConfig {
@Bean
fun authorizationCodeAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> {
val accessTokenResponseClient = DefaultAuthorizationCodeTokenResponseClient()
accessTokenResponseClient.setRestOperations(restTemplate())
return accessTokenResponseClient
}
@Bean
fun refreshTokenAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<OAuth2RefreshTokenGrantRequest> {
val accessTokenResponseClient = DefaultRefreshTokenTokenResponseClient()
accessTokenResponseClient.setRestOperations(restTemplate())
return accessTokenResponseClient
}
@Bean
fun clientCredentialsAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> {
val accessTokenResponseClient = DefaultClientCredentialsTokenResponseClient()
accessTokenResponseClient.setRestOperations(restTemplate())
return accessTokenResponseClient
}
@Bean
fun passwordAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<OAuth2PasswordGrantRequest> {
val accessTokenResponseClient = DefaultPasswordTokenResponseClient()
accessTokenResponseClient.setRestOperations(restTemplate())
return accessTokenResponseClient
}
@Bean
fun jwtBearerAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<JwtBearerGrantRequest> {
val accessTokenResponseClient = DefaultJwtBearerTokenResponseClient()
accessTokenResponseClient.setRestOperations(restTemplate())
return accessTokenResponseClient
}
@Bean
fun tokenExchangeAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<TokenExchangeGrantRequest> {
val accessTokenResponseClient = DefaultTokenExchangeTokenResponseClient()
accessTokenResponseClient.setRestOperations(restTemplate())
return accessTokenResponseClient
}
@Bean
fun restTemplate(): RestTemplate {
// ...
}
}
デフォルトの OAuth2AuthorizedClientManager
がまだ提供されていない場合は、Spring Security によって自動的に発行されます。
この場合、 |
Spring Security 6.2 より前は、このカスタマイズが OAuth2 ログイン (この機能を使用している場合) と OAuth2 クライアントコンポーネントの両方に適用されていることを確認する必要がありました。Spring Security DSL (authorization_code
認可用) と、他の認可型用の OAuth2AuthorizedClientManager
型の Bean の両方を使用する必要がありました。バックグラウンドで何が構成されているかを理解するために、構成は次のようになります。
RestOperations
をカスタマイズする (6.2 より前)Java
Kotlin
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
DefaultAuthorizationCodeTokenResponseClient accessTokenResponseClient =
new DefaultAuthorizationCodeTokenResponseClient();
accessTokenResponseClient.setRestOperations(restTemplate());
http
// ...
.oauth2Login((oauth2Login) -> oauth2Login
.tokenEndpoint((tokenEndpoint) -> tokenEndpoint
.accessTokenResponseClient(accessTokenResponseClient)
)
)
.oauth2Client((oauth2Client) -> oauth2Client
.authorizationCodeGrant((authorizationCode) -> authorizationCode
.accessTokenResponseClient(accessTokenResponseClient)
)
);
return http.build();
}
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
DefaultRefreshTokenTokenResponseClient refreshTokenAccessTokenResponseClient =
new DefaultRefreshTokenTokenResponseClient();
refreshTokenAccessTokenResponseClient.setRestOperations(restTemplate());
DefaultClientCredentialsTokenResponseClient clientCredentialsAccessTokenResponseClient =
new DefaultClientCredentialsTokenResponseClient();
clientCredentialsAccessTokenResponseClient.setRestOperations(restTemplate());
DefaultPasswordTokenResponseClient passwordAccessTokenResponseClient =
new DefaultPasswordTokenResponseClient();
passwordAccessTokenResponseClient.setRestOperations(restTemplate());
DefaultJwtBearerTokenResponseClient jwtBearerAccessTokenResponseClient =
new DefaultJwtBearerTokenResponseClient();
jwtBearerAccessTokenResponseClient.setRestOperations(restTemplate());
JwtBearerOAuth2AuthorizedClientProvider jwtBearerAuthorizedClientProvider =
new JwtBearerOAuth2AuthorizedClientProvider();
jwtBearerAuthorizedClientProvider.setAccessTokenResponseClient(jwtBearerAccessTokenResponseClient);
DefaultTokenExchangeTokenResponseClient tokenExchangeAccessTokenResponseClient =
new DefaultTokenExchangeTokenResponseClient();
tokenExchangeAccessTokenResponseClient.setRestOperations(restTemplate());
TokenExchangeOAuth2AuthorizedClientProvider tokenExchangeAuthorizedClientProvider =
new TokenExchangeOAuth2AuthorizedClientProvider();
tokenExchangeAuthorizedClientProvider.setAccessTokenResponseClient(tokenExchangeAccessTokenResponseClient);
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.authorizationCode()
.refreshToken((refreshToken) -> refreshToken
.accessTokenResponseClient(refreshTokenAccessTokenResponseClient)
)
.clientCredentials((clientCredentials) -> clientCredentials
.accessTokenResponseClient(clientCredentialsAccessTokenResponseClient)
)
.password((password) -> password
.accessTokenResponseClient(passwordAccessTokenResponseClient)
)
.provider(jwtBearerAuthorizedClientProvider)
.provider(tokenExchangeAuthorizedClientProvider)
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
@Bean
public RestTemplate restTemplate() {
// ...
}
}
import org.springframework.security.config.annotation.web.invoke
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
val tokenResponseClient = DefaultAuthorizationCodeTokenResponseClient()
tokenResponseClient.setRestOperations(restTemplate())
http {
// ...
oauth2Login {
tokenEndpoint {
accessTokenResponseClient = tokenResponseClient
}
}
oauth2Client {
authorizationCodeGrant {
accessTokenResponseClient = tokenResponseClient
}
}
}
return http.build()
}
@Bean
fun authorizedClientManager(
clientRegistrationRepository: ClientRegistrationRepository?,
authorizedClientRepository: OAuth2AuthorizedClientRepository?
): OAuth2AuthorizedClientManager {
val refreshTokenAccessTokenResponseClient = DefaultRefreshTokenTokenResponseClient()
refreshTokenAccessTokenResponseClient.setRestOperations(restTemplate())
val clientCredentialsAccessTokenResponseClient = DefaultClientCredentialsTokenResponseClient()
clientCredentialsAccessTokenResponseClient.setRestOperations(restTemplate())
val passwordAccessTokenResponseClient = DefaultPasswordTokenResponseClient()
passwordAccessTokenResponseClient.setRestOperations(restTemplate())
val jwtBearerAccessTokenResponseClient = DefaultJwtBearerTokenResponseClient()
jwtBearerAccessTokenResponseClient.setRestOperations(restTemplate())
val jwtBearerAuthorizedClientProvider = JwtBearerOAuth2AuthorizedClientProvider()
jwtBearerAuthorizedClientProvider.setAccessTokenResponseClient(jwtBearerAccessTokenResponseClient)
val tokenExchangeAccessTokenResponseClient = DefaultTokenExchangeTokenResponseClient()
tokenExchangeAccessTokenResponseClient.setRestOperations(restTemplate())
val tokenExchangeAuthorizedClientProvider = TokenExchangeOAuth2AuthorizedClientProvider()
tokenExchangeAuthorizedClientProvider.setAccessTokenResponseClient(tokenExchangeAccessTokenResponseClient)
val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
.authorizationCode()
.refreshToken { refreshToken ->
refreshToken.accessTokenResponseClient(refreshTokenAccessTokenResponseClient)
}
.clientCredentials { clientCredentials ->
clientCredentials.accessTokenResponseClient(clientCredentialsAccessTokenResponseClient)
}
.password { password ->
password.accessTokenResponseClient(passwordAccessTokenResponseClient)
}
.provider(jwtBearerAuthorizedClientProvider)
.provider(tokenExchangeAuthorizedClientProvider)
.build()
val authorizedClientManager = DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository
)
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
return authorizedClientManager
}
@Bean
fun restTemplate(): RestTemplate {
// ...
}
}