You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue+Spring Cloud Gateway+Keycloak架构请求401问题求助

解决Spring Cloud Gateway作为OAuth2资源服务器时的401问题

以下是几个排查方向和具体解决步骤:

1. 核对网关的OAuth2资源服务器配置

先检查网关的application.yml配置,确保Keycloak的端点、受众与实际一致:

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: http://你的Keycloak地址/realms/你的领域名
          jwk-set-uri: http://你的Keycloak地址/realms/你的领域名/protocol/openid-connect/certs
          audience: 你的SPA客户端ID # 必须和Keycloak里的客户端ID完全匹配

注意Keycloak 22的issuer URI已移除/auth前缀,别用旧格式,否则会导致令牌校验失败。

2. 让网关转发令牌给微服务

网关校验完令牌后,必须把原始令牌转发给下游微服务,否则微服务拿不到合法凭证。写一个全局过滤器即可:

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.http.HttpHeaders;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
public class TokenForwardFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        return ReactiveSecurityContextHolder.getContext()
                .map(ctx -> ctx.getAuthentication())
                .filter(auth -> auth != null && auth.getCredentials() instanceof Jwt)
                .map(Authentication::getCredentials)
                .cast(Jwt.class)
                .doOnNext(jwt -> {
                    // 将原始Bearer令牌添加到请求头转发给微服务
                    exchange.getRequest().mutate()
                            .header(HttpHeaders.AUTHORIZATION, "Bearer " + jwt.getTokenValue())
                            .build();
                })
                .then(chain.filter(exchange));
    }
}

微服务端无需添加任何Keycloak或OAuth2依赖,直接处理请求即可。

3. 检查网关路由配置

确保路由规则未修改或移除Authorization头,示例配置如下:

spring:
  cloud:
    gateway:
      routes:
        - id: 微服务路由ID
          uri: lb://你的微服务名称 # 或直接填写微服务HTTP地址
          predicates:
            - Path=/你的微服务路径/**
          filters:
            - StripPrefix=1 # 按需配置,不需要可删除

如果路由中有自定义过滤器,检查是否误删了Authorization头。

4. 修复跨域(CORS)配置

Vue是跨域请求,网关必须允许携带Authorization头,否则浏览器会拦截请求。添加CORS配置类:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;

import java.util.List;

@Configuration
public class CorsConfig {
    @Bean
    public CorsWebFilter corsWebFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowedOrigins(List.of("http://你的Vue应用地址:端口"));
        config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
        config.setAllowedHeaders(List.of("*"));
        config.setAllowCredentials(true);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);

        return new CorsWebFilter(source);
    }
}

注意AllowedOrigins不要用*,否则AllowCredentials设为true会无效,必须指定具体的Vue地址。

5. 检查Keycloak客户端配置

确认Keycloak里的SPA客户端设置正确:

  • 访问类型选择public(SPA无法存储密钥)
  • 有效重定向URI、Web Origins需包含Vue的地址
  • 启用Authorization Code Flow with PKCE(SPA推荐使用该流程,避免隐式流)
  • 令牌的受众(aud)需包含网关配置里的audience值

6. 校验令牌本身

用Keycloak的令牌 introspect 端点检查令牌有效性:
发送POST请求到http://你的Keycloak地址/realms/你的领域名/protocol/openid-connect/token/introspect,参数携带token=你的Bearer令牌和client_id=你的网关客户端ID(若网关为confidential客户端,还需携带client_secret),查看返回的active是否为true,以及aud、iss等字段是否与网关配置匹配。


内容的提问来源于stack exchange,提问作者Nicenick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 05:07:24