K8s多副本应用环境下Keycloak OIDC认证授权码模式问题求助
部署架构
- 1个Keycloak实例运行在独立Pod中
- 2个后端服务实例(api1、api2)分别运行在不同节点的Pod中
核心问题
使用authorization_code模式时,api1发起认证请求到Keycloak,用户完成验证后,Keycloak的重定向请求被路由到api2,但api2本地会话中没有code_verifier,导致无法调用/protocol/openid-connect/token获取访问令牌。
解决方案
方案一:配置会话粘性,确保重定向到发起请求的实例
在K8s的Ingress或Service层配置会话亲和性,让同一用户的请求始终路由到同一个后端实例:
- 基于Cookie的粘性(推荐):如果使用NGINX Ingress,添加以下注解配置:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: nginx.ingress.kubernetes.io/affinity: "cookie" nginx.ingress.kubernetes.io/session-cookie-name: "backend-sticky-sess" nginx.ingress.kubernetes.io/session-cookie-expires: "172800" # 2天有效期 nginx.ingress.kubernetes.io/session-cookie-max-age: "172800" spec: rules: - host: your-api-domain.com http: paths: - path: / pathType: Prefix backend: service: name: your-api-service port: number: 80 - 基于ClientIP的粘性:如果不需要Ingress,直接在Service中配置:
apiVersion: v1 kind: Service metadata: name: your-api-service spec: selector: app: your-api ports: - port: 80 targetPort: 8080 sessionAffinity: ClientIP sessionAffinityConfig: clientIP: timeoutSeconds: 172800
这种方式能保证Keycloak的重定向请求和初始认证请求落在同一个后端实例上,避免code_verifier找不到的问题。
方案二:使用分布式会话存储,共享code_verifier
放弃Pod本地会话,改用分布式存储让所有后端实例共享会话数据:
- 选择Redis、Memcached这类分布式缓存作为会话存储,比如Spring Boot项目可以集成
spring-session-data-redis,将code_verifier存入Redis集群 - 所有后端实例从共享存储中读取会话数据,不管重定向到哪个实例,都能获取到
code_verifier - 优势:不依赖会话粘性,后端实例可以自由扩缩容,高可用性更强,适合大规模集群场景
注意事项
- 会话粘性方案要考虑Pod销毁的情况:如果原Pod被删除,粘性Cookie会失效,用户需要重新发起认证
- 分布式会话方案要保证存储集群的高可用性,避免Redis单点故障影响整个认证流程
内容的提问来源于stack exchange,提问作者sjgo
相关产品推荐
相关产品推荐

