微服务架构下Kong JWT认证授权相关技术咨询
使用Kong实现统一JWT认证的解决方案
背景概述
你当前的架构中,Kong仅作为代理与负载均衡,由Authentication Service负责生成JWT,其他服务各自解码JWT导致代码冗余。目标是通过Kong的JWT插件统一处理JWT验证与用户信息传递,消除后端服务的重复解码逻辑。
1. 认证服务如何与Kong对接生成包含用户数据的JWT?
Kong的JWT插件不负责生成JWT令牌,它的核心作用是验证JWT的合法性。正确的对接流程如下:
- 认证服务依然负责用户登录校验(调用user_service查询MongoDB),但生成JWT时,必须使用与Kong中对应Consumer绑定的密钥(secret)进行签名。
- 你需要为每个用户在Kong中创建对应的Consumer,并绑定JWT密钥(jwt_secrets):
- 静态场景(固定用户):直接在
kong.yml中声明Consumer与密钥; - 动态场景(用户注册时自动创建):认证服务通过Kong的Admin API(
/consumers和/consumers/{username}/jwt端点)创建Consumer与密钥。
- 静态场景(固定用户):直接在
- 生成JWT时,必须在Payload中包含
kid字段(对应Kong中jwt_secrets的key值),以及用户标识(如sub存用户ID、username存用户名),这样Kong才能关联到对应的Consumer并完成验证。
2. Kong是否需要连接数据库以获取用户数据并生成密钥?
- 如果你使用当前的DB-less模式(
KONG_DATABASE: 'off'),不需要连接数据库,所有Consumer、密钥、服务路由都通过kong.yml定义,或通过Admin API写入内存(重启后需同步到配置文件才能持久化)。 - 如果是数据库模式(如PostgreSQL/Cassandra),Kong会将Consumer、密钥等数据存储到数据库,适合动态创建用户的场景(比如用户注册时自动生成Kong凭证)。
- 注意:Kong本身不生成密钥,密钥需要你在创建Consumer的JWT凭证时指定,或让Kong自动生成(通过Admin API创建时不指定
secret,Kong会生成随机值)。
3. 如何通过Kong解码JWT并传递到其他服务的请求头?
Kong的JWT插件支持将解码后的JWT声明(claims)添加到请求头中,传递给后端服务。只需在插件配置中开启claims_to_headers选项,指定要映射的声明与请求头:
plugins: - name: jwt enabled: true protocols: [http, https] config: key_claim_name: kid claims_to_verify: [exp] claims_to_headers: # 配置声明到请求头的映射 - sub: X-User-ID - username: X-User-Name - role: X-User-Role
后端服务直接读取这些请求头即可,无需再解码JWT。
4. 实现示例(基于你的DB-less模式)
步骤1:更新kong.yml,添加Consumer与JWT密钥
_format_version: "3.0" _transform: true services: # 保留你原有的服务配置 - name: building_service url: http://building_service/building routes: - name: building_service_route paths: [/building] - name: user_service url: http://user_service/user routes: - name: user_service_route paths: [/user] # ...其他服务省略 consumers: - username: user_001 # 对应用户系统的用户ID/用户名 jwt_secrets: - key: user_001_kid # 对应JWT中的kid字段 secret: user_001_secret_key # 签名密钥,认证服务生成JWT时需使用 plugins: - name: jwt enabled: true protocols: [http, https] config: key_claim_name: kid claims_to_verify: [exp] claims_to_headers: - sub: X-User-ID - username: X-User-Name - name: bot-detection - name: rate-limiting config: minute: 60 policy: local
步骤2:认证服务生成JWT的伪代码
import jwt import time def generate_user_jwt(user_id, username): payload = { "kid": "user_001_kid", # 对应Kong中jwt_secrets的key "sub": user_id, "username": username, "exp": time.time() + 3600 # 过期时间1小时 } secret = "user_001_secret_key" # 对应Kong中jwt_secrets的secret return jwt.encode(payload, secret, algorithm="HS256")
步骤3:后端服务获取用户信息示例(Java)
// 直接读取Kong传递的请求头 String userId = request.getHeader("X-User-ID"); String username = request.getHeader("X-User-Name");
步骤4:动态创建Consumer(用户注册场景)
用户注册成功后,认证服务调用Kong Admin API创建对应凭证:
# 创建Consumer curl -X POST http://localhost:8001/consumers \ --data "username=new_user_002" # 绑定JWT密钥 curl -X POST http://localhost:8001/consumers/new_user_002/jwt \ --data "key=new_user_002_kid" \ --data "secret=new_user_002_secret"
5. 你是否存在误解?
你的核心需求(统一JWT验证、消除后端解码冗余)完全可以实现,但有一个关键误解:Kong的JWT插件不负责生成JWT令牌,只负责验证JWT的合法性。之前教程中的“单个Consumer生成JWT”,指的是创建JWT凭证(密钥对),而非生成实际的JWT令牌。
调整后的正确流程:
- 用户登录 → 认证服务校验用户 → 使用Kong对应Consumer的密钥生成JWT → 返回给用户
- 用户携带JWT请求后端服务 → Kong验证JWT合法性 → 解码claims并添加到请求头 → 转发给后端服务
- 后端服务直接读取请求头获取用户信息,无需处理JWT
内容的提问来源于stack exchange,提问作者Ignac96
相关产品推荐
相关产品推荐

