Spring Cloud Gateway中无需GET请求获取OAuth2访问令牌值的方法
无需手动请求获取JWT令牌的实现方案
针对Spring Cloud Gateway场景,你可以通过以下几种方式自动获取并使用JWT令牌,不用手动发起GET请求:
1. 全局过滤器(GlobalFilter)自动处理请求
Spring Cloud Gateway基于过滤器链工作,你可以实现一个全局过滤器,在请求路由到下游服务前自动获取令牌,添加到请求头中,同时提取角色做RBAC校验。
响应式环境下的过滤器实现(Gateway默认是响应式)
import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.security.core.Authentication; import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService; import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; import org.springframework.security.oauth2.core.OAuth2AccessToken; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; @Component public class TokenRelayFilter implements GlobalFilter { private final ReactiveOAuth2AuthorizedClientService authorizedClientService; private final ReactiveClientRegistrationRepository clientRegistrationRepository; public TokenRelayFilter(ReactiveOAuth2AuthorizedClientService authorizedClientService, ReactiveClientRegistrationRepository clientRegistrationRepository) { this.authorizedClientService = authorizedClientService; this.clientRegistrationRepository = clientRegistrationRepository; } @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 从安全上下文获取当前认证用户 return exchange.getPrincipal() .cast(Authentication.class) .flatMap(authentication -> { // 替换成你的Keycloak客户端注册ID(application.yml里配置的) String clientRegistrationId = "keycloak"; // 获取授权客户端 return authorizedClientService.loadAuthorizedClient(clientRegistrationId, authentication.getName()) .map(OAuth2AuthorizedClient::getAccessToken) .map(OAuth2AccessToken::getTokenValue); }) .doOnNext(token -> { // 将令牌添加到请求头,传递给下游服务 exchange.getRequest().mutate() .header("Authorization", "Bearer " + token); // 这里可以提取令牌中的角色,做RBAC校验 // 比如解析JWT,获取roles字段,判断是否有权限访问当前路由 }) .then(chain.filter(exchange)); } }
2. 在业务组件中直接获取令牌
如果需要在非过滤器的组件(比如服务类、拦截器)中获取令牌,可以通过注入ReactiveOAuth2AuthorizedClientService(响应式)或OAuth2AuthorizedClientService(Servlet环境),结合安全上下文获取当前用户,进而拿到令牌:
import org.springframework.security.core.Authentication; import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService; import org.springframework.security.oauth2.core.OAuth2AccessToken; import org.springframework.security.core.context.ReactiveSecurityContextHolder; import org.springframework.stereotype.Service; import reactor.core.publisher.Mono; @Service public class TokenService { private final ReactiveOAuth2AuthorizedClientService authorizedClientService; public TokenService(ReactiveOAuth2AuthorizedClientService authorizedClientService) { this.authorizedClientService = authorizedClientService; } public Mono<String> getCurrentToken() { return ReactiveSecurityContextHolder.getContext() .map(context -> context.getAuthentication()) .flatMap(authentication -> { String clientId = "keycloak"; // 你的客户端ID return authorizedClientService.loadAuthorizedClient(clientId, authentication.getName()) .map(OAuth2AuthorizedClient::getAccessToken) .map(OAuth2AccessToken::getTokenValue); }); } }
关键说明
- 确保你的Spring Cloud Gateway已经正确配置了OAuth2客户端(对接Keycloak),包括
spring.security.oauth2.client.registration.keycloak和spring.security.oauth2.client.provider.keycloak相关配置。 - 前端的session-id会和Spring Security的认证上下文绑定,所以通过
getPrincipal()或安全上下文能拿到当前登录用户的信息,进而关联到对应的OAuth2授权客户端。 - 提取角色做RBAC时,可以用JWT解析库(比如
jjwt)解析令牌,拿到realm_access.roles字段(Keycloak的角色默认存在这里),再结合Spring Security的权限校验机制实现访问控制。
内容的提问来源于stack exchange,提问作者h.martinez
相关产品推荐
相关产品推荐

