2
0

webclient.adoc 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. = WebClient
  2. [NOTE]
  3. ====
  4. The following documentation is for use within Reactive environments.
  5. For Servlet environments, refer to xref:servlet/oauth2/oauth2-client.adoc#oauth2Client-webclient-servlet[ WebClient for Servlet] environments.
  6. ====
  7. Spring Framework has built in support for setting a Bearer token.
  8. ====
  9. .Java
  10. [source,java,role="primary"]
  11. ----
  12. webClient.get()
  13. .headers(h -> h.setBearerAuth(token))
  14. ...
  15. ----
  16. .Kotlin
  17. [source,kotlin,role="secondary"]
  18. ----
  19. webClient.get()
  20. .headers { it.setBearerAuth(token) }
  21. ...
  22. ----
  23. ====
  24. Spring Security builds on this support to provide additional benefits:
  25. * Spring Security will automatically refresh expired tokens (if a refresh token is present)
  26. * If an access token is requested and not present, Spring Security will automatically request the access token.
  27. ** For authorization_code this involves performing the redirect and then replaying the original request
  28. ** For client_credentials the token is simply requested and saved
  29. * Support for the ability to transparently include the current OAuth token or explicitly select which token should be used.
  30. [[webclient-setup]]
  31. == WebClient OAuth2 Setup
  32. The first step is ensuring to setup the `WebClient` correctly.
  33. An example of setting up `WebClient` in a fully reactive environment can be found below:
  34. ====
  35. .Java
  36. [source,java,role="primary"]
  37. ----
  38. @Bean
  39. WebClient webClient(ReactiveClientRegistrationRepository clientRegistrations,
  40. ServerOAuth2AuthorizedClientRepository authorizedClients) {
  41. ServerOAuth2AuthorizedClientExchangeFilterFunction oauth =
  42. new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations, authorizedClients);
  43. // (optional) explicitly opt into using the oauth2Login to provide an access token implicitly
  44. // oauth.setDefaultOAuth2AuthorizedClient(true);
  45. // (optional) set a default ClientRegistration.registrationId
  46. // oauth.setDefaultClientRegistrationId("client-registration-id");
  47. return WebClient.builder()
  48. .filter(oauth)
  49. .build();
  50. }
  51. ----
  52. .Kotlin
  53. [source,kotlin,role="secondary"]
  54. ----
  55. @Bean
  56. fun webClient(clientRegistrations: ReactiveClientRegistrationRepository,
  57. authorizedClients: ServerOAuth2AuthorizedClientRepository): WebClient {
  58. val oauth = ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations, authorizedClients)
  59. // (optional) explicitly opt into using the oauth2Login to provide an access token implicitly
  60. // oauth.setDefaultOAuth2AuthorizedClient(true)
  61. // (optional) set a default ClientRegistration.registrationId
  62. // oauth.setDefaultClientRegistrationId("client-registration-id")
  63. return WebClient.builder()
  64. .filter(oauth)
  65. .build()
  66. }
  67. ----
  68. ====
  69. [[webclient-implicit]]
  70. == Implicit OAuth2AuthorizedClient
  71. If we set `defaultOAuth2AuthorizedClient` to `true` in our setup and the user authenticated with oauth2Login (i.e. OIDC), then the current authentication is used to automatically provide the access token.
  72. Alternatively, if we set `defaultClientRegistrationId` to a valid `ClientRegistration` id, that registration is used to provide the access token.
  73. This is convenient, but in environments where not all endpoints should get the access token, it is dangerous (you might provide the wrong access token to an endpoint).
  74. ====
  75. .Java
  76. [source,java,role="primary"]
  77. ----
  78. Mono<String> body = this.webClient
  79. .get()
  80. .uri(this.uri)
  81. .retrieve()
  82. .bodyToMono(String.class);
  83. ----
  84. .Kotlin
  85. [source,kotlin,role="secondary"]
  86. ----
  87. val body: Mono<String> = webClient
  88. .get()
  89. .uri(this.uri)
  90. .retrieve()
  91. .bodyToMono()
  92. ----
  93. ====
  94. [[webclient-explicit]]
  95. == Explicit OAuth2AuthorizedClient
  96. The `OAuth2AuthorizedClient` can be explicitly provided by setting it on the requests attributes.
  97. In the example below we resolve the `OAuth2AuthorizedClient` using Spring WebFlux or Spring MVC argument resolver support.
  98. However, it does not matter how the `OAuth2AuthorizedClient` is resolved.
  99. ====
  100. .Java
  101. [source,java,role="primary"]
  102. ----
  103. @GetMapping("/explicit")
  104. Mono<String> explicit(@RegisteredOAuth2AuthorizedClient("client-id") OAuth2AuthorizedClient authorizedClient) {
  105. return this.webClient
  106. .get()
  107. .uri(this.uri)
  108. .attributes(oauth2AuthorizedClient(authorizedClient))
  109. .retrieve()
  110. .bodyToMono(String.class);
  111. }
  112. ----
  113. .Kotlin
  114. [source,kotlin,role="secondary"]
  115. ----
  116. @GetMapping("/explicit")
  117. fun explicit(@RegisteredOAuth2AuthorizedClient("client-id") authorizedClient: OAuth2AuthorizedClient?): Mono<String> {
  118. return this.webClient
  119. .get()
  120. .uri(uri)
  121. .attributes(oauth2AuthorizedClient(authorizedClient))
  122. .retrieve()
  123. .bodyToMono()
  124. }
  125. ----
  126. ====
  127. [[webclient-clientregistrationid]]
  128. == clientRegistrationId
  129. Alternatively, it is possible to specify the `clientRegistrationId` on the request attributes and the `WebClient` will attempt to lookup the `OAuth2AuthorizedClient`.
  130. If it is not found, one will automatically be acquired.
  131. ====
  132. .Java
  133. [source,java,role="primary"]
  134. ----
  135. Mono<String> body = this.webClient
  136. .get()
  137. .uri(this.uri)
  138. .attributes(clientRegistrationId("client-id"))
  139. .retrieve()
  140. .bodyToMono(String.class);
  141. ----
  142. .Kotlin
  143. [source,kotlin,role="secondary"]
  144. ----
  145. val body: Mono<String> = this.webClient
  146. .get()
  147. .uri(uri)
  148. .attributes(clientRegistrationId("client-id"))
  149. .retrieve()
  150. .bodyToMono()
  151. ----
  152. ====