I am creating gateway for Spring Boot microservices using Spring Cloud Gateway. Gateway is also responsible for JWT authorization using Spring Security.
public class JwtAuthorizationFilter extends BasicAuthenticationFilter {
...
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
String header = request.getHeader(JwtProperties.HEADER_STRING);
if (header == null || !header.startsWith(JwtProperties.TOKEN_PREFIX)) {
chain.doFilter(request, response);
return;
}
Authentication authentication = getUsernamePasswordAuthentication(request);
SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(request, response);
}
private Authentication getUsernamePasswordAuthentication(HttpServletRequest request) {
String token = request.getHeader(JwtProperties.HEADER_STRING).replace(JwtProperties.TOKEN_PREFIX, "");
DecodedJWT decodedJWT = JWT.require(Algorithm.HMAC512(JwtProperties.SECRET.getBytes())).build().verify(token);
String username = decodedJWT.getSubject();
if (username != null) {
UserPrincipal principal = (UserPrincipal) userPrincipalService.loadUserByUsername(username);
Authentication auth = new UsernamePasswordAuthenticationToken(username, null, principal.getAuthorities());
return auth;
}
return null;
}
}
This filter is registred in configure method like this:
@Configuration
@EnableWebSecurity
public class ApplicationSecurityConfig extends WebSecurityConfigurerAdapter {
...
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilter(new JwtAuthorizationFilter(authenticationManager(), userPrincipalService))
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/login").permitAll()
...
.anyRequest().authenticated();
}
...
}
As you can see, Spring Security is using HttpServletRequest, HttpServletResponse, FilterChain interfaces which belong to spring-boot-starter-web. But that is main problem beacause it's incompatible with spring cloud gateway.
Spring MVC found on classpath, which is incompatible with Spring Cloud Gateway at this time. Please remove spring-boot-starter-web dependency.
Is there any way to avoid this error or any different solution for implementing jwt authorization filter on gateway? Thanks!
In the Documentation of spring cloud gateway it is explicitely stated that this product runs on top of Netty and requires webflux, hence it's not compatible with spring MVC.
The filter that you use (JwtAuthorizationFilter
) is something that belongs to the non-reactive world so you probably should rewrite it with spring security for web flux building blocks.
Disclaimer, I'm not a spring web flux / spring-security expert, but please consider checking This application - it shows how to define JWT secured application with a reactive version of spring security.
So bottom line you should choose whether you want a reactive application or a traditional one and use the relevant technologies but you can't really mix them.