如何为KrakenD网关配置Reference Token(非JWT)并对接Identity Server?
KrakenD 与 Identity Server Reference Token 集成最优方案
核心思路
KrakenD原生不支持Reference Token的解析,最优方案是通过**扩展KrakenD插件,调用Identity Server的Introspection端点(RFC 7662标准)**完成Reference Token的验证与元数据提取,再将元数据注入请求上下文,为限流、计费等逻辑提供依据。
具体实现步骤
1. 配置Identity Server的Introspection端点
启用Identity Server的Introspection端点:在Identity Server的配置中确保
EnableIntrospectionEndpoint设为true。创建KrakenD专属客户端:
- 分配
client_id和client_secret,设置GrantTypes为client_credentials(KrakenD以此身份调用Introspection端点)。 - 给该客户端添加
introspection权限,即在AllowedScopes中包含introspection。
示例客户端配置(Identity Server):
{ "ClientId": "krakend-introspect-client", "ClientSecrets": [ { "Value": "<加密后的密钥>" } ], "AllowedGrantTypes": [ "client_credentials" ], "AllowedScopes": [ "introspection" ] }- 分配
2. 开发KrakenD自定义插件(Go语言)
KrakenD支持Go编写插件,核心逻辑是拦截请求、调用Introspection端点、提取元数据并注入上下文:
从请求头
Authorization中提取Reference Token(格式:Bearer <token>)。向Identity Server的
/connect/introspect端点发送POST请求,携带KrakenD的客户端凭证和待验证的Token。解析响应,提取
client_id、sub(用户ID)、exp(过期时间)等元数据。将元数据存入KrakenD的请求上下文,比如通过
context.Set()或注入自定义请求头。简化版插件代码片段:
package main import ( "context" "net/http" "strings" "encoding/json" ) type IntrospectionResponse struct { Active bool `json:"active"` ClientID string `json:"client_id"` Sub string `json:"sub"` Exp int64 `json:"exp"` } func IntrospectMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // 提取Token authHeader := r.Header.Get("Authorization") if authHeader == "" || !strings.HasPrefix(authHeader, "Bearer ") { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } token := strings.TrimPrefix(authHeader, "Bearer ") // 调用Identity Server Introspection端点 client := &http.Client{} req, _ := http.NewRequest("POST", "https://your-idp/connect/introspect", strings.NewReader("token="+token)) req.SetBasicAuth("krakend-introspect-client", "<客户端密钥>") req.Header.Set("Content-Type", "application/x-www-form-urlencoded") resp, err := client.Do(req) if err != nil || resp.StatusCode != http.StatusOK { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } defer resp.Body.Close() var introspectResp IntrospectionResponse json.NewDecoder(resp.Body).Decode(&introspectResp) if !introspectResp.Active { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } // 将元数据注入上下文 ctx := context.WithValue(r.Context(), "client_id", introspectResp.ClientID) ctx = context.WithValue(ctx, "user_id", introspectResp.Sub) next.ServeHTTP(w, r.WithContext(ctx)) }) }
3. 集成插件到KrakenD并配置限流/计费
- 将编译好的插件引入KrakenD配置,在
extra_config中指定插件路径。 - 配置KrakenD的限流组件,基于上下文的
client_id设置差异化规则:{ "endpoints": [ { "endpoint": "/api/service", "extra_config": { "github.com/devopsfaith/krakend-ratelimit/juju/router": { "maxRate": 100, "clientMaxRate": 50, "strategy": "client_id" // 基于client_id限流 } } } ] } - 计费逻辑可通过后续微服务读取请求上下文的
client_id/user_id,统计调用次数并生成账单。
关键优化点
- 缓存Introspection结果:在插件中添加缓存层(如Redis),缓存已验证Token的元数据,有效期设为Token的剩余过期时间,减少对Identity Server的重复调用。
- HTTPS通信:确保KrakenD与Identity Server之间的请求使用HTTPS,避免凭证或Token泄露。
- 错误处理:针对Introspection端点的超时、错误响应,直接返回401/403,避免无效请求流入后端服务。
内容的提问来源于stack exchange,提问作者Mourad
相关产品推荐
相关产品推荐

