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角色信息,添加到认证对象中
验证要点
- 确保配置文件中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
- 启动网关后,用Keycloak颁发的JWT令牌请求网关路由,验证认证是否正常生效
内容的提问来源于stack exchange,提问作者KaraKaplan
相关产品推荐
相关产品推荐

