|
@@ -68,8 +68,8 @@ See xref:getting-spring-security.adoc[] for additional options when not using Sp
|
|
|
|
|
|
Consider the following use cases for OAuth2 Resource Server:
|
|
Consider the following use cases for OAuth2 Resource Server:
|
|
|
|
|
|
-* <<oauth2-resource-server-access-token,I want to protect access to the API using OAuth2>> (authorization server provides JWT or opaque access token)
|
|
|
|
-* <<oauth2-resource-server-custom-jwt,I want to protect access to the API using a JWT>> (custom token)
|
|
|
|
|
|
+* I want to <<oauth2-resource-server-access-token,protect access to the API using OAuth2>> (authorization server provides JWT or opaque access token)
|
|
|
|
+* I want to <<oauth2-resource-server-custom-jwt,protect access to the API using a JWT>> (custom token)
|
|
|
|
|
|
[[oauth2-resource-server-access-token]]
|
|
[[oauth2-resource-server-access-token]]
|
|
=== Protect Access with an OAuth2 Access Token
|
|
=== Protect Access with an OAuth2 Access Token
|
|
@@ -399,9 +399,10 @@ See xref:getting-spring-security.adoc[] for additional options when not using Sp
|
|
Consider the following use cases for OAuth2 Client:
|
|
Consider the following use cases for OAuth2 Client:
|
|
|
|
|
|
* I want to <<oauth2-client-log-users-in,log users in using OAuth 2.0 or OpenID Connect 1.0>>
|
|
* I want to <<oauth2-client-log-users-in,log users in using OAuth 2.0 or OpenID Connect 1.0>>
|
|
-* I want to <<oauth2-client-access-protected-resources,use `RestClient` to obtain an access token for users in order to access a third-party API>>
|
|
|
|
|
|
+* I want to <<oauth2-client-access-protected-resources,use `RestClient` to obtain an access token for users>> in order to access a third-party API
|
|
|
|
+* I want to <<oauth2-client-access-protected-resources-webclient,use `WebClient` to obtain an access token for users>> in order to access a third-party API
|
|
* I want to <<oauth2-client-access-protected-resources-current-user,do both>> (log users in _and_ access a third-party API)
|
|
* I want to <<oauth2-client-access-protected-resources-current-user,do both>> (log users in _and_ access a third-party API)
|
|
-* I want to <<oauth2-client-access-protected-resources-webclient,use `WebClient` to obtain an access token for users in order to access a third-party API>>
|
|
|
|
|
|
+* I want to <<oauth2-client-client-credentials,use the `client_credentials` grant type>> to obtain a single token per application
|
|
* I want to <<oauth2-client-enable-extension-grant-type,enable an extension grant type>>
|
|
* I want to <<oauth2-client-enable-extension-grant-type,enable an extension grant type>>
|
|
* I want to <<oauth2-client-customize-existing-grant-type,customize an existing grant type>>
|
|
* I want to <<oauth2-client-customize-existing-grant-type,customize an existing grant type>>
|
|
* I want to <<oauth2-client-customize-request-parameters,customize token request parameters>>
|
|
* I want to <<oauth2-client-customize-request-parameters,customize token request parameters>>
|
|
@@ -694,6 +695,229 @@ class MessagesController(private val restClient: RestClient) {
|
|
----
|
|
----
|
|
=====
|
|
=====
|
|
|
|
|
|
|
|
+[[oauth2-client-access-protected-resources-webclient]]
|
|
|
|
+=== Access Protected Resources with `WebClient`
|
|
|
|
+
|
|
|
|
+Making requests to a third party API that is protected by OAuth2 is a core use case of OAuth2 Client.
|
|
|
|
+This is accomplished by authorizing a client (represented by the `OAuth2AuthorizedClient` class in Spring Security) and accessing protected resources by placing a `Bearer` token in the `Authorization` header of an outbound request.
|
|
|
|
+
|
|
|
|
+The following example configures the application to act as an OAuth2 Client capable of requesting protected resources from a third party API:
|
|
|
|
+
|
|
|
|
+.Configure OAuth2 Client
|
|
|
|
+[tabs]
|
|
|
|
+=====
|
|
|
|
+Java::
|
|
|
|
++
|
|
|
|
+[source,java,role="primary"]
|
|
|
|
+----
|
|
|
|
+@Configuration
|
|
|
|
+@EnableWebSecurity
|
|
|
|
+public class SecurityConfig {
|
|
|
|
+
|
|
|
|
+ @Bean
|
|
|
|
+ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
|
|
|
+ http
|
|
|
|
+ // ...
|
|
|
|
+ .oauth2Client(Customizer.withDefaults());
|
|
|
|
+ return http.build();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+----
|
|
|
|
+
|
|
|
|
+Kotlin::
|
|
|
|
++
|
|
|
|
+[source,kotlin,role="secondary"]
|
|
|
|
+----
|
|
|
|
+import org.springframework.security.config.annotation.web.invoke
|
|
|
|
+
|
|
|
|
+@Configuration
|
|
|
|
+@EnableWebSecurity
|
|
|
|
+class SecurityConfig {
|
|
|
|
+
|
|
|
|
+ @Bean
|
|
|
|
+ fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
|
|
|
+ http {
|
|
|
|
+ // ...
|
|
|
|
+ oauth2Client { }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return http.build()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+----
|
|
|
|
+=====
|
|
|
|
+
|
|
|
|
+[NOTE]
|
|
|
|
+====
|
|
|
|
+The above example does not provide a way to log users in.
|
|
|
|
+You can use any other login mechanism (such as `formLogin()`).
|
|
|
|
+See the <<oauth2-client-access-protected-resources-current-user,previous section>> for an example combining `oauth2Client()` with `oauth2Login()`.
|
|
|
|
+====
|
|
|
|
+
|
|
|
|
+In addition to the above configuration, the application requires at least one `ClientRegistration` to be configured through the use of a `ClientRegistrationRepository` bean.
|
|
|
|
+The following example configures an `InMemoryClientRegistrationRepository` bean using Spring Boot configuration properties:
|
|
|
|
+
|
|
|
|
+[source,yaml]
|
|
|
|
+----
|
|
|
|
+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
|
|
|
|
+----
|
|
|
|
+
|
|
|
|
+In addition to configuring Spring Security to support OAuth2 Client features, you will also need to decide how you will be accessing protected resources and configure your application accordingly.
|
|
|
|
+Spring Security provides implementations of `OAuth2AuthorizedClientManager` for obtaining access tokens that can be used to access protected resources.
|
|
|
|
+
|
|
|
|
+[TIP]
|
|
|
|
+====
|
|
|
|
+Spring Security registers a default `OAuth2AuthorizedClientManager` bean for you when one does not exist.
|
|
|
|
+====
|
|
|
|
+
|
|
|
|
+<<oauth2-client-access-protected-resources,Instead of configuring a `RestClient`>>, another way to use an `OAuth2AuthorizedClientManager` is via an `ExchangeFilterFunction` that intercepts requests through a `WebClient`.
|
|
|
|
+To use `WebClient`, you will need to add the `spring-webflux` dependency along with a reactive client implementation:
|
|
|
|
+
|
|
|
|
+.Add Spring WebFlux Dependency
|
|
|
|
+[tabs]
|
|
|
|
+======
|
|
|
|
+Gradle::
|
|
|
|
++
|
|
|
|
+[source,gradle,role="primary"]
|
|
|
|
+----
|
|
|
|
+implementation 'org.springframework:spring-webflux'
|
|
|
|
+implementation 'io.projectreactor.netty:reactor-netty'
|
|
|
|
+----
|
|
|
|
+
|
|
|
|
+Maven::
|
|
|
|
++
|
|
|
|
+[source,maven,role="secondary"]
|
|
|
|
+----
|
|
|
|
+<dependency>
|
|
|
|
+ <groupId>org.springframework</groupId>
|
|
|
|
+ <artifactId>spring-webflux</artifactId>
|
|
|
|
+</dependency>
|
|
|
|
+<dependency>
|
|
|
|
+ <groupId>io.projectreactor.netty</groupId>
|
|
|
|
+ <artifactId>reactor-netty</artifactId>
|
|
|
|
+</dependency>
|
|
|
|
+----
|
|
|
|
+======
|
|
|
|
+
|
|
|
|
+The following example uses the default `OAuth2AuthorizedClientManager` to configure a `WebClient` capable of accessing protected resources by placing `Bearer` tokens in the `Authorization` header of each request:
|
|
|
|
+
|
|
|
|
+.Configure `WebClient` with `ExchangeFilterFunction`
|
|
|
|
+[tabs]
|
|
|
|
+=====
|
|
|
|
+Java::
|
|
|
|
++
|
|
|
|
+[source,java,role="primary"]
|
|
|
|
+----
|
|
|
|
+@Configuration
|
|
|
|
+public class WebClientConfig {
|
|
|
|
+
|
|
|
|
+ @Bean
|
|
|
|
+ public WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {
|
|
|
|
+ ServletOAuth2AuthorizedClientExchangeFilterFunction filter =
|
|
|
|
+ new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
|
|
|
|
+ return WebClient.builder()
|
|
|
|
+ .apply(filter.oauth2Configuration())
|
|
|
|
+ .build();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+----
|
|
|
|
+
|
|
|
|
+Kotlin::
|
|
|
|
++
|
|
|
|
+[source,kotlin,role="secondary"]
|
|
|
|
+----
|
|
|
|
+@Configuration
|
|
|
|
+class WebClientConfig {
|
|
|
|
+
|
|
|
|
+ @Bean
|
|
|
|
+ fun webClient(authorizedClientManager: OAuth2AuthorizedClientManager): WebClient {
|
|
|
|
+ val filter = ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager)
|
|
|
|
+ return WebClient.builder()
|
|
|
|
+ .apply(filter.oauth2Configuration())
|
|
|
|
+ .build()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+----
|
|
|
|
+=====
|
|
|
|
+
|
|
|
|
+This configured `WebClient` can be used as in the following example:
|
|
|
|
+
|
|
|
|
+.Use `WebClient` to Access Protected Resources
|
|
|
|
+[tabs]
|
|
|
|
+=====
|
|
|
|
+Java::
|
|
|
|
++
|
|
|
|
+[source,java,role="primary"]
|
|
|
|
+----
|
|
|
|
+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) {
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+----
|
|
|
|
+
|
|
|
|
+Kotlin::
|
|
|
|
++
|
|
|
|
+[source,kotlin,role="secondary"]
|
|
|
|
+----
|
|
|
|
+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-client-access-protected-resources-current-user]]
|
|
[[oauth2-client-access-protected-resources-current-user]]
|
|
=== Access Protected Resources for the Current User
|
|
=== Access Protected Resources for the Current User
|
|
|
|
|
|
@@ -921,128 +1145,36 @@ Unlike the <<oauth2-client-accessing-protected-resources-example,previous exampl
|
|
This is because it can be derived from the currently logged in user.
|
|
This is because it can be derived from the currently logged in user.
|
|
====
|
|
====
|
|
|
|
|
|
-[[oauth2-client-access-protected-resources-webclient]]
|
|
|
|
-=== Access Protected Resources with `WebClient`
|
|
|
|
-
|
|
|
|
-Making requests to a third party API that is protected by OAuth2 is a core use case of OAuth2 Client.
|
|
|
|
-This is accomplished by authorizing a client (represented by the `OAuth2AuthorizedClient` class in Spring Security) and accessing protected resources by placing a `Bearer` token in the `Authorization` header of an outbound request.
|
|
|
|
-
|
|
|
|
-The following example configures the application to act as an OAuth2 Client capable of requesting protected resources from a third party API:
|
|
|
|
-
|
|
|
|
-.Configure OAuth2 Client
|
|
|
|
-[tabs]
|
|
|
|
-=====
|
|
|
|
-Java::
|
|
|
|
-+
|
|
|
|
-[source,java,role="primary"]
|
|
|
|
-----
|
|
|
|
-@Configuration
|
|
|
|
-@EnableWebSecurity
|
|
|
|
-public class SecurityConfig {
|
|
|
|
-
|
|
|
|
- @Bean
|
|
|
|
- public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
|
|
|
- http
|
|
|
|
- // ...
|
|
|
|
- .oauth2Client(Customizer.withDefaults());
|
|
|
|
- return http.build();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-}
|
|
|
|
-----
|
|
|
|
-
|
|
|
|
-Kotlin::
|
|
|
|
-+
|
|
|
|
-[source,kotlin,role="secondary"]
|
|
|
|
-----
|
|
|
|
-import org.springframework.security.config.annotation.web.invoke
|
|
|
|
-
|
|
|
|
-@Configuration
|
|
|
|
-@EnableWebSecurity
|
|
|
|
-class SecurityConfig {
|
|
|
|
-
|
|
|
|
- @Bean
|
|
|
|
- fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
|
|
|
- http {
|
|
|
|
- // ...
|
|
|
|
- oauth2Client { }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return http.build()
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-}
|
|
|
|
-----
|
|
|
|
-=====
|
|
|
|
|
|
+[[oauth2-client-client-credentials]]
|
|
|
|
+=== Use the Client Credentials Grant
|
|
|
|
|
|
[NOTE]
|
|
[NOTE]
|
|
====
|
|
====
|
|
-The above example does not provide a way to log users in.
|
|
|
|
-You can use any other login mechanism (such as `formLogin()`).
|
|
|
|
-See the <<oauth2-client-access-protected-resources-current-user,previous section>> for an example combining `oauth2Client()` with `oauth2Login()`.
|
|
|
|
|
|
+This section focuses on additional considerations for the client credentials grant type.
|
|
|
|
+See <<oauth2-client-access-protected-resources>> for general setup and usage with all grant types.
|
|
====
|
|
====
|
|
|
|
|
|
-In addition to the above configuration, the application requires at least one `ClientRegistration` to be configured through the use of a `ClientRegistrationRepository` bean.
|
|
|
|
-The following example configures an `InMemoryClientRegistrationRepository` bean using Spring Boot configuration properties:
|
|
|
|
-
|
|
|
|
-[source,yaml]
|
|
|
|
-----
|
|
|
|
-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
|
|
|
|
-----
|
|
|
|
-
|
|
|
|
-In addition to configuring Spring Security to support OAuth2 Client features, you will also need to decide how you will be accessing protected resources and configure your application accordingly.
|
|
|
|
-Spring Security provides implementations of `OAuth2AuthorizedClientManager` for obtaining access tokens that can be used to access protected resources.
|
|
|
|
|
|
+The https://tools.ietf.org/html/rfc6749#section-1.3.4[client credentials grant] allows a client to obtain an `access_token` on behalf of itself.
|
|
|
|
+The client credentials grant is a simple flow that does not involve a resource owner (i.e. a user).
|
|
|
|
|
|
-[TIP]
|
|
|
|
|
|
+[WARNING]
|
|
====
|
|
====
|
|
-Spring Security registers a default `OAuth2AuthorizedClientManager` bean for you when one does not exist.
|
|
|
|
|
|
+It is important to note that typical use of the client credentials grant implies that any request (or user) can potentially obtain an access token and make protected resources requests to a resource server.
|
|
|
|
+Exercise caution when designing applications to ensure that users cannot make unauthorized requests since every request will be able to obtain an access token.
|
|
====
|
|
====
|
|
|
|
|
|
-Another way to use an `OAuth2AuthorizedClientManager` is via an `ExchangeFilterFunction` that intercepts requests through a `WebClient`.
|
|
|
|
-To use `WebClient`, you will need to add the `spring-webflux` dependency along with a reactive client implementation:
|
|
|
|
|
|
+When obtaining access tokens within a web application where users can log in, the default behavior of Spring Security is to obtain an access token per user.
|
|
|
|
|
|
-.Add Spring WebFlux Dependency
|
|
|
|
-[tabs]
|
|
|
|
-======
|
|
|
|
-Gradle::
|
|
|
|
-+
|
|
|
|
-[source,gradle,role="primary"]
|
|
|
|
-----
|
|
|
|
-implementation 'org.springframework:spring-webflux'
|
|
|
|
-implementation 'io.projectreactor.netty:reactor-netty'
|
|
|
|
-----
|
|
|
|
-
|
|
|
|
-Maven::
|
|
|
|
-+
|
|
|
|
-[source,maven,role="secondary"]
|
|
|
|
-----
|
|
|
|
-<dependency>
|
|
|
|
- <groupId>org.springframework</groupId>
|
|
|
|
- <artifactId>spring-webflux</artifactId>
|
|
|
|
-</dependency>
|
|
|
|
-<dependency>
|
|
|
|
- <groupId>io.projectreactor.netty</groupId>
|
|
|
|
- <artifactId>reactor-netty</artifactId>
|
|
|
|
-</dependency>
|
|
|
|
-----
|
|
|
|
-======
|
|
|
|
|
|
+[NOTE]
|
|
|
|
+====
|
|
|
|
+By default, access tokens are scoped to the principal name of the current user which means every user will receive a unique access token.
|
|
|
|
+====
|
|
|
|
|
|
-The following example uses the default `OAuth2AuthorizedClientManager` to configure a `WebClient` capable of accessing protected resources by placing `Bearer` tokens in the `Authorization` header of each request:
|
|
|
|
|
|
+Clients using the client credentials grant typically require access tokens to be scoped to the application instead of to individual users so there is only one access token per application.
|
|
|
|
+In order to scope access tokens to the application, you will need to set a strategy for resolving a custom principal name.
|
|
|
|
+The following example does this by configuring a `RestClient` with the `RequestAttributePrincipalResolver`:
|
|
|
|
|
|
-.Configure `WebClient` with `ExchangeFilterFunction`
|
|
|
|
|
|
+.Configure `RestClient` for `client_credentials`
|
|
[tabs]
|
|
[tabs]
|
|
=====
|
|
=====
|
|
Java::
|
|
Java::
|
|
@@ -1050,14 +1182,15 @@ Java::
|
|
[source,java,role="primary"]
|
|
[source,java,role="primary"]
|
|
----
|
|
----
|
|
@Configuration
|
|
@Configuration
|
|
-public class WebClientConfig {
|
|
|
|
|
|
+public class RestClientConfig {
|
|
|
|
|
|
@Bean
|
|
@Bean
|
|
- public WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {
|
|
|
|
- ServletOAuth2AuthorizedClientExchangeFilterFunction filter =
|
|
|
|
- new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
|
|
|
|
- return WebClient.builder()
|
|
|
|
- .apply(filter.oauth2Configuration())
|
|
|
|
|
|
+ public RestClient restClient(OAuth2AuthorizedClientManager authorizedClientManager) {
|
|
|
|
+ OAuth2ClientHttpRequestInterceptor requestInterceptor =
|
|
|
|
+ new OAuth2ClientHttpRequestInterceptor(authorizedClientManager);
|
|
|
|
+ requestInterceptor.setPrincipalResolver(new RequestAttributePrincipalResolver());
|
|
|
|
+ return RestClient.builder()
|
|
|
|
+ .requestInterceptor(requestInterceptor)
|
|
.build();
|
|
.build();
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1069,13 +1202,14 @@ Kotlin::
|
|
[source,kotlin,role="secondary"]
|
|
[source,kotlin,role="secondary"]
|
|
----
|
|
----
|
|
@Configuration
|
|
@Configuration
|
|
-class WebClientConfig {
|
|
|
|
|
|
+class RestClientConfig {
|
|
|
|
|
|
@Bean
|
|
@Bean
|
|
- fun webClient(authorizedClientManager: OAuth2AuthorizedClientManager): WebClient {
|
|
|
|
- val filter = ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager)
|
|
|
|
- return WebClient.builder()
|
|
|
|
- .apply(filter.oauth2Configuration())
|
|
|
|
|
|
+ fun restClient(authorizedClientManager: OAuth2AuthorizedClientManager): RestClient {
|
|
|
|
+ val requestInterceptor = OAuth2ClientHttpRequestInterceptor(authorizedClientManager)
|
|
|
|
+ requestInterceptor.setPrincipalResolver(RequestAttributePrincipalResolver())
|
|
|
|
+ return RestClient.builder()
|
|
|
|
+ .requestInterceptor(requestInterceptor)
|
|
.build()
|
|
.build()
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1083,34 +1217,37 @@ class WebClientConfig {
|
|
----
|
|
----
|
|
=====
|
|
=====
|
|
|
|
|
|
-This configured `WebClient` can be used as in the following example:
|
|
|
|
|
|
+With the above configuration in place, a principal name can be specified for each request.
|
|
|
|
+The following example demonstrates how to scope access tokens to the application by specifying a principal name:
|
|
|
|
|
|
-.Use `WebClient` to Access Protected Resources
|
|
|
|
|
|
+.Scope Access Tokens to the Application
|
|
[tabs]
|
|
[tabs]
|
|
=====
|
|
=====
|
|
Java::
|
|
Java::
|
|
+
|
|
+
|
|
[source,java,role="primary"]
|
|
[source,java,role="primary"]
|
|
----
|
|
----
|
|
-import static org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId;
|
|
|
|
|
|
+import static org.springframework.security.oauth2.client.web.client.RequestAttributeClientRegistrationIdResolver.clientRegistrationId;
|
|
|
|
+import static org.springframework.security.oauth2.client.web.client.RequestAttributePrincipalResolver.principal;
|
|
|
|
|
|
@RestController
|
|
@RestController
|
|
public class MessagesController {
|
|
public class MessagesController {
|
|
|
|
|
|
- private final WebClient webClient;
|
|
|
|
|
|
+ private final RestClient restClient;
|
|
|
|
|
|
- public MessagesController(WebClient webClient) {
|
|
|
|
- this.webClient = webClient;
|
|
|
|
|
|
+ public MessagesController(RestClient restClient) {
|
|
|
|
+ this.restClient = restClient;
|
|
}
|
|
}
|
|
|
|
|
|
@GetMapping("/messages")
|
|
@GetMapping("/messages")
|
|
public ResponseEntity<List<Message>> messages() {
|
|
public ResponseEntity<List<Message>> messages() {
|
|
- return this.webClient.get()
|
|
|
|
|
|
+ Message[] messages = this.restClient.get()
|
|
.uri("http://localhost:8090/messages")
|
|
.uri("http://localhost:8090/messages")
|
|
.attributes(clientRegistrationId("my-oauth2-client"))
|
|
.attributes(clientRegistrationId("my-oauth2-client"))
|
|
|
|
+ .attributes(principal("my-application"))
|
|
.retrieve()
|
|
.retrieve()
|
|
- .toEntityList(Message.class)
|
|
|
|
- .block();
|
|
|
|
|
|
+ .body(Message[].class);
|
|
|
|
+ return ResponseEntity.ok(Arrays.asList(messages));
|
|
}
|
|
}
|
|
|
|
|
|
public record Message(String message) {
|
|
public record Message(String message) {
|
|
@@ -1123,19 +1260,23 @@ Kotlin::
|
|
+
|
|
+
|
|
[source,kotlin,role="secondary"]
|
|
[source,kotlin,role="secondary"]
|
|
----
|
|
----
|
|
-import org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId
|
|
|
|
|
|
+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
|
|
@RestController
|
|
-class MessagesController(private val webClient: WebClient) {
|
|
|
|
|
|
+class MessagesController(private val restClient: RestClient) {
|
|
|
|
|
|
@GetMapping("/messages")
|
|
@GetMapping("/messages")
|
|
fun messages(): ResponseEntity<List<Message>> {
|
|
fun messages(): ResponseEntity<List<Message>> {
|
|
- return webClient.get()
|
|
|
|
|
|
+ val messages = restClient.get()
|
|
.uri("http://localhost:8090/messages")
|
|
.uri("http://localhost:8090/messages")
|
|
.attributes(clientRegistrationId("my-oauth2-client"))
|
|
.attributes(clientRegistrationId("my-oauth2-client"))
|
|
|
|
+ .attributes(principal("my-application"))
|
|
.retrieve()
|
|
.retrieve()
|
|
- .toEntityList<Message>()
|
|
|
|
- .block()!!
|
|
|
|
|
|
+ .body<Array<Message>>()!!
|
|
|
|
+ .toList()
|
|
|
|
+ return ResponseEntity.ok(messages)
|
|
}
|
|
}
|
|
|
|
|
|
data class Message(val message: String)
|
|
data class Message(val message: String)
|
|
@@ -1144,6 +1285,11 @@ class MessagesController(private val webClient: WebClient) {
|
|
----
|
|
----
|
|
=====
|
|
=====
|
|
|
|
|
|
|
|
+[NOTE]
|
|
|
|
+====
|
|
|
|
+When specifying a principal name via attributes as in the above example, there will only be a single access token and it will be used for all requests.
|
|
|
|
+====
|
|
|
|
+
|
|
[[oauth2-client-enable-extension-grant-type]]
|
|
[[oauth2-client-enable-extension-grant-type]]
|
|
=== Enable an Extension Grant Type
|
|
=== Enable an Extension Grant Type
|
|
|
|
|