Spring Cloud Gateway OAuth2资源服务器权限配置与令牌转发问题
Spring Cloud Gateway OAuth2资源服务器配置与服务间令牌转发问题
一、配置网关的授权规则
因为网关基于WebFlux环境,你需要通过SecurityWebFilterChain Bean定义细粒度的授权规则,替换默认的全局认证逻辑,直接在配置类中编写路径匹配和权限校验即可:
@Configuration @EnableWebFluxSecurity public class GatewaySecurityConfig { @Bean public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http .authorizeExchange(exchanges -> exchanges // 开放无需授权的接口(比如健康检查、服务发现端点) .pathMatchers("/actuator/**", "/eureka/**").permitAll() // 对service1的接口要求用户拥有指定scope权限 .pathMatchers("/api/service1/**").hasAuthority("SCOPE_default-user-scope") // 管理员接口要求对应权限 .pathMatchers("/api/admin/**").hasAuthority("SCOPE_admin-scope") // 剩余所有请求必须经过认证 .anyExchange().authenticated() ) .oauth2ResourceServer(oauth2 -> oauth2 .jwt(jwt -> jwt.jwkSetUri("你的JWK集合地址")) ); return http.build(); } }
注意:JWT中的scope字段会被自动转换为带SCOPE_前缀的权限,因此可以直接用hasAuthority做校验。如果需要更复杂的权限判断,也可以用access()方法结合自定义权限验证器实现。
二、后端服务间调用的令牌处理
分两种场景处理:
场景1:网关转发请求到后端服务
默认情况下,Spring Cloud Gateway会原样转发所有请求头,包括携带Bearer令牌的Authorization头。只要你的后端服务也配置成OAuth2资源服务器(和网关一样,引入spring-boot-starter-oauth2-resource-server依赖、配置JWK地址),就能直接接收并校验令牌,不需要额外做转发处理。
场景2:后端服务主动调用其他服务
如果是服务内部主动发起对其他服务的调用(比如服务A处理请求时主动调用服务B),需要手动将当前上下文的用户令牌传递过去,可以通过请求拦截器实现,用WebClient或RestTemplate都可以:
用WebClient实现(适配WebFlux服务)
@Bean public WebClient webClient(ReactiveSecurityContextHolder reactiveSecurityContextHolder) { return WebClient.builder() .filter((request, next) -> { return reactiveSecurityContextHolder.getContext() .map(SecurityContext::getAuthentication) .cast(JwtAuthenticationToken.class) .map(tokenAuth -> tokenAuth.getToken().getTokenValue()) .defaultIfEmpty("") .flatMap(token -> { ClientRequest authorizedRequest = ClientRequest.from(request) .header(HttpHeaders.AUTHORIZATION, "Bearer " + token) .build(); return next.exchange(authorizedRequest); }); }) .build(); }
用RestTemplate实现(适配Servlet服务)
@Bean public RestTemplate restTemplate() { RestTemplate restTemplate = new RestTemplate(); restTemplate.getInterceptors().add((request, body, execution) -> { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth instanceof JwtAuthenticationToken) { String token = ((JwtAuthenticationToken) auth).getToken().getTokenValue(); request.getHeaders().set(HttpHeaders.AUTHORIZATION, "Bearer " + token); } return execution.execute(request, body); }); return restTemplate; }
后续服务间调用时,直接注入使用配置好的WebClient/RestTemplate,就能自动携带当前用户的Bearer令牌。
内容的提问来源于stack exchange,提问作者Dirk
相关产品推荐
相关产品推荐

