mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-06-12 07:02:13 +00:00
Add example for setting up client credentials
Closes gh-15304
This commit is contained in:
parent
dab6950231
commit
9b89fc2f1f
@ -69,8 +69,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)
|
* I want to <<oauth2-resource-server-access-token,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-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
|
||||||
@ -393,13 +393,13 @@ 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:
|
||||||
|
|
||||||
* <<oauth2-client-log-users-in,I want to 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>>
|
||||||
* <<oauth2-client-access-protected-resources,I want to obtain an access token for users in order to access a third-party API>>
|
* I want to <<oauth2-client-access-protected-resources,obtain an access token for users>> in order to access a third-party API
|
||||||
* <<oauth2-client-access-protected-resources-current-user,I want to 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)
|
||||||
* <<oauth2-client-enable-extension-grant-type,I want to enable an extension grant type>>
|
* I want to <<oauth2-client-enable-extension-grant-type,enable an extension grant type>>
|
||||||
* <<oauth2-client-customize-existing-grant-type,I want to customize an existing grant type>>
|
* I want to <<oauth2-client-customize-existing-grant-type,customize an existing grant type>>
|
||||||
* <<oauth2-client-customize-request-parameters,I want to customize token request parameters>>
|
* I want to <<oauth2-client-customize-request-parameters,customize token request parameters>>
|
||||||
* <<oauth2-client-customize-web-client,I want to customize the `WebClient` used by OAuth2 Client components>>
|
* I want to <<oauth2-client-customize-web-client,customize the `WebClient` used by OAuth2 Client components>>
|
||||||
|
|
||||||
[[oauth2-client-log-users-in]]
|
[[oauth2-client-log-users-in]]
|
||||||
=== Log Users In with OAuth2
|
=== Log Users In with OAuth2
|
||||||
|
@ -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)
|
* I want to <<oauth2-resource-server-access-token,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-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]]
|
[[oauth2-client-client-credentials]]
|
||||||
=== Access Protected Resources with `WebClient`
|
=== Use the Client Credentials Grant
|
||||||
|
|
||||||
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]
|
[NOTE]
|
||||||
====
|
====
|
||||||
The above example does not provide a way to log users in.
|
This section focuses on additional considerations for the client credentials grant type.
|
||||||
You can use any other login mechanism (such as `formLogin()`).
|
See <<oauth2-client-access-protected-resources>> for general setup and usage with all grant types.
|
||||||
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 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 following example configures an `InMemoryClientRegistrationRepository` bean using Spring Boot configuration properties:
|
The client credentials grant is a simple flow that does not involve a resource owner (i.e. a user).
|
||||||
|
|
||||||
[source,yaml]
|
[WARNING]
|
||||||
----
|
|
||||||
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.
|
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`.
|
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.
|
||||||
To use `WebClient`, you will need to add the `spring-webflux` dependency along with a reactive client implementation:
|
|
||||||
|
|
||||||
.Add Spring WebFlux Dependency
|
[NOTE]
|
||||||
[tabs]
|
====
|
||||||
======
|
By default, access tokens are scoped to the principal name of the current user which means every user will receive a unique access token.
|
||||||
Gradle::
|
====
|
||||||
+
|
|
||||||
[source,gradle,role="primary"]
|
|
||||||
----
|
|
||||||
implementation 'org.springframework:spring-webflux'
|
|
||||||
implementation 'io.projectreactor.netty:reactor-netty'
|
|
||||||
----
|
|
||||||
|
|
||||||
Maven::
|
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.
|
||||||
[source,maven,role="secondary"]
|
The following example does this by configuring a `RestClient` with the `RequestAttributePrincipalResolver`:
|
||||||
----
|
|
||||||
<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 `RestClient` for `client_credentials`
|
||||||
|
|
||||||
.Configure `WebClient` with `ExchangeFilterFunction`
|
|
||||||
[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) {
|
public RestClient restClient(OAuth2AuthorizedClientManager authorizedClientManager) {
|
||||||
ServletOAuth2AuthorizedClientExchangeFilterFunction filter =
|
OAuth2ClientHttpRequestInterceptor requestInterceptor =
|
||||||
new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
|
new OAuth2ClientHttpRequestInterceptor(authorizedClientManager);
|
||||||
return WebClient.builder()
|
requestInterceptor.setPrincipalResolver(new RequestAttributePrincipalResolver());
|
||||||
.apply(filter.oauth2Configuration())
|
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 {
|
fun restClient(authorizedClientManager: OAuth2AuthorizedClientManager): RestClient {
|
||||||
val filter = ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager)
|
val requestInterceptor = OAuth2ClientHttpRequestInterceptor(authorizedClientManager)
|
||||||
return WebClient.builder()
|
requestInterceptor.setPrincipalResolver(RequestAttributePrincipalResolver())
|
||||||
.apply(filter.oauth2Configuration())
|
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) {
|
public MessagesController(RestClient restClient) {
|
||||||
this.webClient = webClient;
|
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)
|
.body(Message[].class);
|
||||||
.block();
|
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>()
|
.body<Array<Message>>()!!
|
||||||
.block()!!
|
.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
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user