Spring Webflux: Security configuration
This post will be about how I got configured Spring Webflux Security. The code can be found on https://github.com/duyleduc/spring-boot-webflux-security
Default Security Setup
Add the spring-boot-security in your pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
This will add @EnableReactiveMethodSecurity containing the initial/default security configuration. To authenticate using username/password, we need a database to store these informations.
Spring boot webflux only supports NoSQL database, in this example, we’ll use reactive mongodb, so add this dependency to your pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
</dependency>
Spring Security Configuration Class
For the security configuration, we’ll create a class SecurityConfiguration with these annotations: @EnableReactiveMethodSecurity and @EnableWebFluxSecurity.
@Configuration
@EnableReactiveMethodSecurity
@EnableWebFluxSecurity
public class SecurityConfiguration {
}
To complete this configuration, we can take advantage of class ServerHttpSecurity. Next step, provide the following config:
// Disable login form
http.httpBasic().disable()
.formLogin().disable()
.csrf().disable()
.logout().disable();// Add a filter with Authorization on header http.addFilterAt(webFilter(),SecurityWebFiltersOrder.AUTHORIZATION)
.authorizeExchange()
// Passing a white list endpoint, do not need to
// authenticate
.pathMatchers(AUTH_WHITELIST).permitAll()
.anyExchange().authenticated();
Also, we’ll need a user details service. We must implement the ReactiveUserDetailsService interface
public class ReactiveUserDetailsServiceImpl implements ReactiveUserDetailsService {}
we’ll create an implementation of ServerWebExchangeMatcher to check the authorization header token
public class JWTHeadersExchangeMatcher implements ServerWebExchangeMatcher {}
Then, in the SecurityConfiguration class, create a bean of AuthenticationWebFilter:
@Bean
public AuthenticationWebFilter webFilter() {
AuthenticationWebFilter authenticationWebFilter = new AuthenticationWebFilter(repositoryReactiveAuthenticationManager());
authenticationWebFilter.setAuthenticationConverter(new TokenAuthenticationConverter(tokenProvider));
authenticationWebFilter.setRequiresAuthenticationMatcher(new JWTHeadersExchangeMatcher());
authenticationWebFilter.setSecurityContextRepository(new WebSessionServerSecurityContextRepository());
return authenticationWebFilter;
}
AuthenticationWebFilter needs a token converter, this class will convert a token from ServerWebExchange (HttpRequest not exists anymore in webflux) to a Mono<Authentication>
public class TokenAuthenticationConverter implements Function<ServerWebExchange, Mono<Authentication>> {}
Customize AuthenticateManager
When you want to customize your (JWT) token, for example, add some customized claims, we could create your own AuthenticateManager by the following code:
public class JWTReactiveAuthenticationManin ager implements ReactiveAuthenticationManager {@Override
public Mono<Authentication> authenticate(final Authentication authentication) {
if (authentication.isAuthenticated()) {
// This can prevent call method get user from database multi times
return Mono.just(authentication);
} // Customize your implementation here
return Mono.just(authentication)
.switchIfEmpty(Mono.defer(this::raiseBadCredentials))
.cast(UsernamePasswordAuthenticationToken.class)
.flatMap(this::authenticateToken)
.publishOn(Schedulers.parallel())
}
}
This is some feedbacks from some playgrounds about Spring Security in Webflux. All codes are in my github repo: