Весенний облачный шлюз с spring-boot-starter-web

#spring-boot #spring-security #jwt #spring-cloud-gateway

#пружинный ботинок #spring-безопасность #jwt #весна-облачный шлюз

Вопрос:

Я создаю шлюз для микросервисов Spring Boot, используя Spring Cloud Gateway. Шлюз также отвечает за авторизацию JWT с помощью 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;
    }

}
 

Этот фильтр регистрируется в методе configure следующим образом:

 @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();
        
    }
...
}
 

Как вы можете видеть, Spring Security использует интерфейсы HttpServletRequest, HttpServletResponse, FilterChain, которые принадлежат spring-boot-starter-web. Но это основная проблема, потому что она несовместима с 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.
 

Есть ли какой-либо способ избежать этой ошибки или какое-либо другое решение для реализации фильтра авторизации jwt на шлюзе?
Спасибо!

Ответ №1:

В документации spring cloud gateway прямо указано, что этот продукт работает поверх Netty и требует webflux, следовательно, он несовместим с spring MVC.

Используемый вами фильтр ( JwtAuthorizationFilter ) относится к нереактивному миру, поэтому вам, вероятно, следует переписать его с помощью spring security для строительных блоков web flux.

Отказ от ответственности, я не специалист по spring web flux / spring-security, но, пожалуйста, рассмотрите возможность проверки этого приложения — в нем показано, как определить защищенное приложение JWT с реактивной версией spring security.

Итак, в итоге вы должны выбрать, хотите ли вы реактивное приложение или традиционное, и использовать соответствующие технологии, но вы не можете их смешивать.