webflux.adoc 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. [[jc-webflux]]
  2. = WebFlux Security
  3. Spring Security's WebFlux support relies on a `WebFilter` and works the same for Spring WebFlux and Spring WebFlux.Fn.
  4. You can find a few sample applications that demonstrate the code below:
  5. * Hello WebFlux {gh-samples-url}/reactive/webflux/java/hello-security[hellowebflux]
  6. * Hello WebFlux.Fn {gh-samples-url}/reactive/webflux-fn/hello-security[hellowebfluxfn]
  7. * Hello WebFlux Method {gh-samples-url}/reactive/webflux/java/method[hellowebflux-method]
  8. == Minimal WebFlux Security Configuration
  9. You can find a minimal WebFlux Security configuration below:
  10. .Minimal WebFlux Security Configuration
  11. ====
  12. .Java
  13. [source,java,role="primary"]
  14. -----
  15. @EnableWebFluxSecurity
  16. public class HelloWebfluxSecurityConfig {
  17. @Bean
  18. public MapReactiveUserDetailsService userDetailsService() {
  19. UserDetails user = User.withDefaultPasswordEncoder()
  20. .username("user")
  21. .password("user")
  22. .roles("USER")
  23. .build();
  24. return new MapReactiveUserDetailsService(user);
  25. }
  26. }
  27. -----
  28. .Kotlin
  29. [source,kotlin,role="secondary"]
  30. -----
  31. @EnableWebFluxSecurity
  32. class HelloWebfluxSecurityConfig {
  33. @Bean
  34. fun userDetailsService(): ReactiveUserDetailsService {
  35. val userDetails = User.withDefaultPasswordEncoder()
  36. .username("user")
  37. .password("user")
  38. .roles("USER")
  39. .build()
  40. return MapReactiveUserDetailsService(userDetails)
  41. }
  42. }
  43. -----
  44. ====
  45. This configuration provides form and http basic authentication, sets up authorization to require an authenticated user for accessing any page, sets up a default log in page and a default log out page, sets up security related HTTP headers, CSRF protection, and more.
  46. == Explicit WebFlux Security Configuration
  47. You can find an explicit version of the minimal WebFlux Security configuration below:
  48. .Explicit WebFlux Security Configuration
  49. ====
  50. .Java
  51. [source,java,role="primary"]
  52. -----
  53. @Configuration
  54. @EnableWebFluxSecurity
  55. public class HelloWebfluxSecurityConfig {
  56. @Bean
  57. public MapReactiveUserDetailsService userDetailsService() {
  58. UserDetails user = User.withDefaultPasswordEncoder()
  59. .username("user")
  60. .password("user")
  61. .roles("USER")
  62. .build();
  63. return new MapReactiveUserDetailsService(user);
  64. }
  65. @Bean
  66. public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
  67. http
  68. .authorizeExchange(exchanges -> exchanges
  69. .anyExchange().authenticated()
  70. )
  71. .httpBasic(withDefaults())
  72. .formLogin(withDefaults());
  73. return http.build();
  74. }
  75. }
  76. -----
  77. .Kotlin
  78. [source,kotlin,role="secondary"]
  79. -----
  80. import org.springframework.security.config.web.server.invoke
  81. @Configuration
  82. @EnableWebFluxSecurity
  83. class HelloWebfluxSecurityConfig {
  84. @Bean
  85. fun userDetailsService(): ReactiveUserDetailsService {
  86. val userDetails = User.withDefaultPasswordEncoder()
  87. .username("user")
  88. .password("user")
  89. .roles("USER")
  90. .build()
  91. return MapReactiveUserDetailsService(userDetails)
  92. }
  93. @Bean
  94. fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
  95. return http {
  96. authorizeExchange {
  97. authorize(anyExchange, authenticated)
  98. }
  99. formLogin { }
  100. httpBasic { }
  101. }
  102. }
  103. }
  104. -----
  105. ====
  106. [NOTE]
  107. Make sure that you import the `invoke` function in your Kotlin class, sometimes the IDE will not auto-import it causing compilation issues.
  108. This configuration explicitly sets up all the same things as our minimal configuration.
  109. From here you can easily make the changes to the defaults.
  110. You can find more examples of explicit configuration in unit tests, by searching https://github.com/spring-projects/spring-security/search?q=path%3Aconfig%2Fsrc%2Ftest%2F+EnableWebFluxSecurity[EnableWebFluxSecurity in the `config/src/test/` directory].
  111. [[jc-webflux-multiple-filter-chains]]
  112. === Multiple Chains Support
  113. You can configure multiple `SecurityWebFilterChain` instances to separate configuration by ``RequestMatcher``s.
  114. For example, you can isolate configuration for URLs that start with `/api`, like so:
  115. ====
  116. .Java
  117. [source,java,role="primary"]
  118. ----
  119. @Configuration
  120. @EnableWebFluxSecurity
  121. static class MultiSecurityHttpConfig {
  122. @Order(Ordered.HIGHEST_PRECEDENCE) <1>
  123. @Bean
  124. SecurityWebFilterChain apiHttpSecurity(ServerHttpSecurity http) {
  125. http
  126. .securityMatcher(new PathPatternParserServerWebExchangeMatcher("/api/**")) <2>
  127. .authorizeExchange((exchanges) -> exchanges
  128. .anyExchange().authenticated()
  129. )
  130. .oauth2ResourceServer(OAuth2ResourceServerSpec::jwt); <3>
  131. return http.build();
  132. }
  133. @Bean
  134. SecurityWebFilterChain webHttpSecurity(ServerHttpSecurity http) { <4>
  135. http
  136. .authorizeExchange((exchanges) -> exchanges
  137. .anyExchange().authenticated()
  138. )
  139. .httpBasic(withDefaults()); <5>
  140. return http.build();
  141. }
  142. @Bean
  143. ReactiveUserDetailsService userDetailsService() {
  144. return new MapReactiveUserDetailsService(
  145. PasswordEncodedUser.user(), PasswordEncodedUser.admin());
  146. }
  147. }
  148. ----
  149. .Kotlin
  150. [source,kotlin,role="secondary"]
  151. ----
  152. import org.springframework.security.config.web.server.invoke
  153. @Configuration
  154. @EnableWebFluxSecurity
  155. open class MultiSecurityHttpConfig {
  156. @Order(Ordered.HIGHEST_PRECEDENCE) <1>
  157. @Bean
  158. open fun apiHttpSecurity(http: ServerHttpSecurity): SecurityWebFilterChain {
  159. return http {
  160. securityMatcher(PathPatternParserServerWebExchangeMatcher("/api/**")) <2>
  161. authorizeExchange {
  162. authorize(anyExchange, authenticated)
  163. }
  164. oauth2ResourceServer {
  165. jwt { } <3>
  166. }
  167. }
  168. }
  169. @Bean
  170. open fun webHttpSecurity(http: ServerHttpSecurity): SecurityWebFilterChain { <4>
  171. return http {
  172. authorizeExchange {
  173. authorize(anyExchange, authenticated)
  174. }
  175. httpBasic { } <5>
  176. }
  177. }
  178. @Bean
  179. open fun userDetailsService(): ReactiveUserDetailsService {
  180. return MapReactiveUserDetailsService(
  181. PasswordEncodedUser.user(), PasswordEncodedUser.admin()
  182. )
  183. }
  184. }
  185. ----
  186. ====
  187. <1> Configure a `SecurityWebFilterChain` with an `@Order` to specify which `SecurityWebFilterChain` Spring Security should consider first
  188. <2> Use `PathPatternParserServerWebExchangeMatcher` to state that this `SecurityWebFilterChain` will only apply to URL paths that start with `/api/`
  189. <3> Specify the authentication mechanisms that will be used for `/api/**` endpoints
  190. <4> Create another instance of `SecurityWebFilterChain` with lower precedence to match all other URLs
  191. <5> Specify the authentication mechanisms that will be used for the rest of the application
  192. Spring Security will select one `SecurityWebFilterChain` `@Bean` for each request.
  193. It will match the requests in order by the `securityMatcher` definition.
  194. In this case, that means that if the URL path starts with `/api`, then Spring Security will use `apiHttpSecurity`.
  195. If the URL does not start with `/api` then Spring Security will default to `webHttpSecurity`, which has an implied `securityMatcher` that matches any request.