Spring Cloud网关如何携带Basic Auth认证信息路由请求至微服务
Basic Auth网关认证后微服务获取认证信息问题解决方案
问题描述
我拥有Gateway和HelloWorld两个微服务,在Gateway中使用Basic Auth完成用户认证,认证通过后请求会路由至HelloWorld微服务,但存在认证信息未同步传递的问题:HelloWorld的/secured接口中Authentication参数为null,触发空指针异常。
HelloWorld核心代码
@RequestMapping("/") @RestController public class HelloController { @GetMapping("/hello") public String hello() { return "Hello, world!"; } @GetMapping("/secured") public String secured(Authentication auth) { // !!! auth == null -> NullPointerException !!! return "This page is secured. Your role is " + auth.getAuthorities() .stream() .map(GrantedAuthority::getAuthority) .collect(Collectors.joining(", ")) + "."; } }
Gateway安全配置代码
@Configuration @EnableWebFluxSecurity public class WebSecurityConfig { @Bean public SecurityWebFilterChain securityFilterChain(ServerHttpSecurity http, ReactiveAuthenticationManager authManager) throws Exception { return http .authorizeExchange(request -> request .pathMatchers("/hello").permitAll() .pathMatchers("/secured").authenticated() .anyExchange().permitAll() ) .csrf(csrf -> csrf.disable()) .httpBasic(httpBasic -> httpBasic.authenticationManager(authManager)) .build(); } // 其他安全配置... }
Gateway路由配置代码
@SpringBootApplication @EnableDiscoveryClient public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class, args); } @Bean public RouteLocator myRoutes(RouteLocatorBuilder builder) { return builder.routes() .route(p -> p .path("/**") .uri("http://localhost:8081")) .build(); } }
问题解答
1. 如何在Gateway中传递Authentication信息至微服务,避免重复认证
可以通过网关添加全局过滤器传递认证信息,再在微服务中解析并构建Security上下文的方式解决,具体步骤如下:
步骤1:Gateway中添加全局过滤器,注入认证信息到请求头
创建全局过滤器,从网关的Security上下文提取已认证的用户信息和权限,放入自定义请求头中:
@Component public class AuthenticationHeaderFilter implements GlobalFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { return exchange.getPrincipal() .cast(Authentication.class) .flatMap(auth -> { // 注入用户名到请求头 ServerHttpRequest modifiedRequest = exchange.getRequest().mutate() .header("X-User-Name", auth.getName()) // 注入权限列表(逗号分隔)到请求头 .header("X-User-Authorities", auth.getAuthorities().stream() .map(GrantedAuthority::getAuthority) .collect(Collectors.joining(","))) .build(); return chain.filter(exchange.mutate().request(modifiedRequest).build()); }) // 无认证信息的请求(如/hello)直接放行 .switchIfEmpty(chain.filter(exchange)); } }
步骤2:HelloWorld微服务中添加过滤器,构建Security上下文
创建过滤器,从请求头提取认证信息,构建Authentication对象并放入Security上下文,这样接口的Authentication参数就会被Spring自动注入:
@Component public class AuthenticationContextFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String userName = request.getHeader("X-User-Name"); String authoritiesStr = request.getHeader("X-User-Authorities"); if (userName != null && authoritiesStr != null) { // 解析权限列表 List<GrantedAuthority> authorities = Arrays.stream(authoritiesStr.split(",")) .map(SimpleGrantedAuthority::new) .collect(Collectors.toList()); // 构建认证对象 Authentication auth = new UsernamePasswordAuthenticationToken(userName, null, authorities); // 放入Security上下文 SecurityContextHolder.getContext().setAuthentication(auth); } filterChain.doFilter(request, response); } }
步骤3:HelloWorld微服务调整Security配置
关闭微服务自身的Basic Auth认证(由网关统一处理),同时确保接口权限校验正常:
@Configuration @EnableWebSecurity public class HelloWorldSecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { return http .authorizeHttpRequests(auth -> auth .requestMatchers("/hello").permitAll() .requestMatchers("/secured").authenticated() .anyRequest().permitAll() ) .httpBasic(httpBasic -> httpBasic.disable()) .csrf(csrf -> csrf.disable()) .build(); } }
2. 统一在Gateway做认证,还是每个微服务重复实现更常见
统一在Gateway做认证是微服务架构中更常见的最佳实践,原因如下:
- 减少重复代码:无需在每个微服务中重复编写认证逻辑,降低维护成本和代码冗余。
- 集中管控:认证规则、权限策略可在网关统一配置,修改时只需调整网关,无需逐个更新微服务。
- 性能优化:避免每个微服务重复执行认证流程,减少系统整体开销。
- 安全边界清晰:网关作为入口统一拦截未认证请求,微服务可专注于业务逻辑;同时可配置微服务仅允许来自网关的请求,提升安全性。
需要注意的是:微服务不能完全依赖网关的认证,建议添加二次校验机制,比如配置IP白名单仅允许网关IP访问,或者对传递的认证信息添加签名校验,防止绕过网关直接访问微服务的风险。
内容的提问来源于stack exchange,提问作者Arkadi
相关产品推荐
相关产品推荐

