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

Spring Cloud Gateway集成Keycloak时遇IllegalStateException等异常

解决Spring Cloud Gateway集成Keycloak认证的问题

问题根源分析

核心问题是将Servlet栈的Spring Security配置直接迁移到了WebFlux架构的Spring Cloud Gateway,两者安全模型完全不兼容:

  • Spring Cloud Gateway基于Reactor/WebFlux,需使用ServerHttpSecurity而非Servlet的HttpSecurity
  • 引入的keycloak-policy-enforcer是Servlet专属依赖,直接依赖jakarta.servlet.Filter,导致类找不到错误
  • 多余的jakarta.servlet-api依赖完全没必要,网关不依赖Servlet容器

分步解决方案

1. 修正Gradle依赖配置

移除Servlet相关的Keycloak依赖和无效的Servlet API依赖,保留核心网关与OAuth2资源服务器依赖:

plugins {
    java
    id("org.springframework.boot") version "3.2.3"
    id("io.spring.dependency-management") version "1.1.4"
}

group = "tubitak.bilgem.bte.apron.authservice"
version = "0.0.1-SNAPSHOT"

java {
    sourceCompatibility = JavaVersion.VERSION_17
}

repositories {
    mavenCentral()
}

extra["springCloudVersion"] = "2023.0.0"

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-actuator")
    implementation("org.springframework.boot:spring-boot-starter-data-jpa")
    implementation("org.springframework.cloud:spring-cloud-starter-gateway")

    // 核心OAuth2资源服务器依赖,已兼容Keycloak JWT
    implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server")
    implementation("org.springframework.boot:spring-boot-starter-security")
    
    // 仅保留Keycloak核心API(如需操作Keycloak),移除Servlet版policy-enforcer
    implementation("org.keycloak:keycloak-core:24.0.4")

    compileOnly("org.projectlombok:lombok:1.18.30")
    annotationProcessor("org.projectlombok:lombok:1.18.30")

    runtimeOnly("org.postgresql:postgresql")

    testImplementation("org.springframework.boot:spring-boot-starter-test")
    testImplementation("io.projectreactor:reactor-test")

    testImplementation("org.keycloak:keycloak-admin-client:24.0.4")
    testImplementation("org.springframework.security:spring-security-test")
    testImplementation("org.keycloak:keycloak-test-helper:24.0.4")

    testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}

dependencyManagement {
    imports {
        mavenBom("org.springframework.cloud:spring-cloud-dependencies:${property("springCloudVersion")}")
    }
}

tasks.withType<Test> {
    useJUnitPlatform()
}

2. 重写WebFlux风格的Security配置类

替换Servlet版HttpSecurity为WebFlux的ServerHttpSecurity,使用@EnableWebFluxSecurity:

@Configuration
@EnableWebFluxSecurity(debug = true)
public class KeycloakSecurityConfiguration {
    @Value("${spring.security.oauth2.resourceserver.jwt.jwk-set-uri}")
    String jwkSetUri;

    @Bean
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
        return http
                // WebFlux的CORS配置
                .cors(cors -> cors.configurationSource(request -> {
                    CorsConfiguration configuration = new CorsConfiguration();
                    configuration.setAllowedOrigins(List.of("*"));
                    configuration.setAllowedMethods(List.of("*"));
                    configuration.setAllowedHeaders(List.of("*"));
                    return configuration;
                }))
                .csrf(ServerHttpSecurity.CsrfSpec::disable)
                // 授权规则
                .authorizeExchange(exchanges -> exchanges
                        .anyExchange().authenticated())
                // OAuth2资源服务器JWT配置
                .oauth2ResourceServer(oauth2 -> oauth2
                        .jwt(jwt -> jwt.decoder(jwtDecoder())))
                // WebFlux默认无状态,无需额外配置Session
                .build();
    }

    @Bean
    public JwtDecoder jwtDecoder() {
        return NimbusJwtDecoder.withJwkSetUri(this.jwkSetUri).build();
    }
}

3. 替代Keycloak Policy Enforcer

Keycloak官方暂无WebFlux版Policy Enforcer实现,若需细粒度授权,可通过以下方式替代:

  • 用Spring Security的@PreAuthorize注解结合Keycloak JWT声明(如scope、roles)
  • 自定义JwtAuthenticationConverter解析Keycloak角色信息,添加到认证对象中

验证要点

  1. 确保配置文件中Keycloak参数正确:
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://your-keycloak-server/auth/realms/your-realm/protocol/openid-connect/certs
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://your-keycloak-server/auth/realms/your-realm
  1. 启动网关后,用Keycloak颁发的JWT令牌请求网关路由,验证认证是否正常生效

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 17:33:18