Day 13 / 共 20 天 · 第 3 周 AI/插件/消费者

消费者与鉴权

今天看"谁能访问我的 API"这套鉴权。核心发现:所谓"消费者"其实就是 key-auth 插件的一个全局实例,"给路由加鉴权"就是往 allow list 里加名字。理解这层映射,鉴权就不神秘了。

📍 你在整门课的位置 · 第 3 周 AI/插件/消费者(Day 11-15)
D11 AI供应商/路由 D12 插件管理 D13 消费者鉴权 D14 路由/服务源 D15 MCP管理
L01

消费者是什么

🤔 痛点:不做鉴权会出什么事故? 你把大模型 API 挂上网关,忘了配鉴权——第二天账单爆了:任何知道地址的人都在免费调用你的 OpenAI,Token 费用哗哗地烧。"谁能访问我的 API"必须能控制。
💡 本质:门禁卡 + 门口的白名单 消费者就像"发给合作方的门禁卡"(一张卡 = 一个调用方 + 一把 Key);给路由配鉴权,就是在这扇门口贴一张"只有这几张卡能进"的白名单。访客刷卡(请求带 Key)→ 门卫(网关)核对卡号 → 对了放行、错了拦下。Console 管的就是"发卡"和"给门配名单"两件事。
📝 举个例子 请求带 Authorization: Bearer sk-abc123 打到路由 order-api → 网关查 key-auth 的 keys 是否有 sk-abc123,再查这条路由的 allow list 是否放行对应消费者 → 命中则放行,否则返回 401

消费者(Consumer)代表"一个 API 调用方",带一份凭据(API Key)。给某条路由配上"只允许消费者 A、B 访问",未带正确 Key 的请求就被拦。

用生活例子理解 消费者就像"发给合作方的门禁卡"。你先登记若干张卡(消费者 + 各自的 Key),再在某扇门(路由)上设置"只有这几张卡能进"。访客刷卡(请求带 Key),网关核对卡号,对了放行、错了拦下。Console 管的就是"发卡"和"给门配名单"两件事。
L02

ConsumersController

ConsumersController.java/v1/consumers:45-49):list(:58)、add(:67validate(false) 凭据值必填)、query(:78)、put(:88validate(true) 凭据值可空)、delete(:105)。

读法:add 时 validate(false) 表示"凭据值必须填"(新建就要给 Key);put 时 validate(true) 表示"凭据值可以空"(改其他字段时不强制重填 Key)。同一个校验方法用一个布尔参数区分新建/更新的宽严——小技巧。
L03

存进 key-auth 全局实例

ConsumerServiceImpl.addOrUpdate:64-79):取/建 key-auth 插件的全局实例(setInternal(true) + setGlobalTarget + initDefaultGlobalConfigs)→ handler.saveConsumeraddOrUpdateAll

消费者没有独立存储! 你以为消费者会存在一张"用户表"里?不——所有消费者都存进 key-auth 这个鉴权插件的全局实例配置(它的 consumers 数组)。因为消费者本来就是给 key-auth 插件用的数据,直接存进插件配置最自然。Console 的一切都落成插件/CRD/ConfigMap——消费者也不例外。
L04

凭据 → 插件配置

KeyAuthCredentialHandler.saveConsumer:125-212)是"凭据 → 插件配置"映射核心,按 KeyAuthCredentialSourcein_header / in_query

  • BEARER:key 固定 Authorization,值加 Bearer 前缀(:188-195
  • HEADER:自定义请求头
  • QUERY:查询参数

keys/credentials,强制 global_auth=false:210);不同消费者用相同 key 值会报错(:165-168)。

读法:三种"Key 放哪"对应三种客户端习惯:放 Authorization 头(Bearer)、放自定义头、放 URL 参数。global_auth=false 表示"不是全局强制鉴权"——具体哪条路由要鉴权由 allow list 决定(下一讲)。
L05

目前只支持 API Key

ConsumerServiceImpl 的 Handler 注册表(:51-56只注册了 KeyAuthCredentialHandlerjwt-auth 只有插件名常量(BuiltInPluginName.java:40没有对应 Handler。凭据类型 CredentialType.java 唯一值就是 key-auth

现状 + 扩展点:Console 目前只支持 API Key 一种鉴权。想加 JWT 鉴权?扩展点很清晰——新增一个 CredentialHandler 实现,注册进 ConsumerServiceImpl.java:51-56 的表里即可。这又是一个绝佳的"动手改进"练习。
L06

allow list 机制

请求带 Key key-auth 插件ROUTE 实例 · allow[] 在名单 → 放行 ✅ 不在 → 401 ⛔ ADD / REMOVE REPLACE TOGGLE_ONLY ↑ 改名单的四种操作
allow list = 某 ROUTE 作用域 key-auth 实例里的 allow 数组;前端"勾选允许的消费者"就走 ADD/REMOVE/REPLACE/TOGGLE_ONLY 四种操作。

"某路由允许哪些消费者"用 allow list 表达。ConsumerServiceImpl

  • listAllowLists:120-155)/ getAllowList:157-192,禁 GLOBAL)
  • updateAllowList:194-278):空 credentialTypes 默认 KEY_AUTH,按 ADD/REMOVE/REPLACE/TOGGLE_ONLY 改 allow
allow list 到底是什么? 它就是"某个 ROUTE 作用域的 key-auth 插件实例"里的 allow 数组——列出这条路由放行哪些消费者,加上 enabled(是否开启鉴权)。四种操作:ADD 加人、REMOVE 移人、REPLACE 整体替换、TOGGLE_ONLY 只切换开关不改名单。前端"给路由勾选允许的消费者"就调这个。
L07

路由鉴权桥梁

🧭 第一人称:你是一次"给路由加鉴权"的保存请求 你带着"路由 order-api 只允许消费者 A、B"这份设置进入 RouteServiceImpl.add。路由本身先转成 Ingress 写下去;接着你被交给 writeAuthConfigResources——它把你携带的 RouteAuthConfig 翻译成一次 AllowList 的 REPLACE 操作,落到那条路由对应的 ROUTE 作用域 key-auth 实例的 allow 数组里。于是"路由"和"鉴权"两个模块,就靠这一步接上了。下次读取时 ingress2Route 再把 allow 反向回填成 authConfig 给前端展示。

回到 Day 10 的悬念——为什么 RouteServiceImpl.addwriteAuthConfigResources?答案在 RouteServiceImpl.java

  • add/update 后 writeAuthConfigResources:167-175):把路由的 RouteAuthConfig 转成 AllowList,用 REPLACE 写入。
  • 读取时 ingress2Route 回填 RouteAuthConfig
  • delete 时清 ROUTE 作用域的 key-auth 实例(:156-165)。
读法:这就把"路由"和"鉴权"两个模块接起来了:路由上的鉴权设置 ↔ 一个 ROUTE 作用域 key-auth 插件实例的 allow list。Route 里的 authConfig(Day 09 见过的字段)就是这层桥梁的载体。
L08

今日小结 + 动手

🧠 今天你应该能回答

  • 消费者是什么?它存在哪(不是数据库)?
  • 三种凭据 source(BEARER/HEADER/QUERY)的区别?
  • 目前支持几种鉴权?加 JWT 的扩展点在哪?
  • allow list 的四种操作?路由鉴权和 key-auth 实例怎么对应?

✋ 动手

cd /Users/bitmart/work/codes/github/higress-group/higress-console/backend/sdk/src/main/java/com/alibaba/higress/sdk
sed -n '51,79p' service/consumer/ConsumerServiceImpl.java
sed -n '125,212p' service/consumer/KeyAuthCredentialHandler.java
sed -n '194,278p' service/consumer/ConsumerServiceImpl.java
sed -n '156,175p' service/RouteServiceImpl.java
明天预告 · Day 14路由与服务来源管理——服务为什么只读、服务来源(8 种注册中心)如何全部存进一个 McpBridge CR、认证信息如何单独存 Secret。
← Day 12 Day 14 · 路由/服务源 →