Spring 带有 spring-boot-starter-web 的云网关

Spring Cloud Gateway with spring-boot-starter-web

我正在使用 Spring 云网关为 Spring 引导微服务创建网关。网关还负责使用 Spring 安全性进行 JWT 授权。

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;
    }

}

此过滤器在配置方法中注册如下:

@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 安全性正在使用属于 spring-boot-starter-web 的 HttpServletRequest、HttpServletResponse、FilterChain 接口。但这是主要问题,因为它与spring 云网关不兼容。

Spring MVC found on classpath, which is incompatible with Spring Cloud Gateway at this time. Please remove spring-boot-starter-web dependency.

有什么方法可以避免这个错误,或者有什么不同的解决方案可以在网关上实现 jwt 授权过滤器吗? 谢谢!

Documentation of spring cloud gateway 中明确指出该产品运行在 Netty 之上并且需要 webflux,因此它与 spring MVC 不兼容。

您使用的过滤器 (JwtAuthorizationFilter) 属于非反应性世界,因此您可能应该使用 spring 网络通量构建块的安全性重写它。

免责声明,我不是 spring 网络流量/spring-安全专家,但请考虑检查 This application - 它展示了如何使用反应式定义 JWT 安全应用程序spring 安全版本。

所以最重要的是你应该选择你想要反应式应用程序还是传统应用程序并使用相关技术但你不能真正混合它们。