Apache APISIX key-auth 插件完全指南:基于 Consumer 的 API 密钥身份验证实战
2026/9/15 12:46:26 网站建设 项目流程

Apache APISIX key-auth 插件完全指南:基于 Consumer 的 API 密钥身份验证实战

【免费下载链接】apisixThe Cloud-Native API Gateway项目地址: https://gitcode.com/GitHub_Trending/ap/apisix

key-auth是 Apache APISIX 中最基础、使用最广泛的认证类插件,它通过在请求的 Header 或 Query String 中携带 API Key 来验证调用方身份。本文以官方文档 key-auth 插件说明 为主线,结合 插件源码、单元测试 与 Consumer 机制 的实现细节,完整讲解插件的属性配置、Consumer 与 Route 的配合方式、测试验证、Secret 集成与加密存储,帮助你在实际网关场景中正确、安全地落地 API 密钥认证。

插件概述与工作原理

key-auth插件用于向 Route 或 Service 添加身份验证密钥(API Key),它本身并不存储密钥,而是依赖 APISIX 的Consumer(消费者)机制:先在 Consumer 上声明唯一的key,再在 Route 或 Service 上挂载key-auth插件,请求到达网关后,插件从请求的 Header 或 Query String 中取出 key,与 Consumer 注册的 key 进行比对,从而完成身份验证。

从源码结构看,key-auth通过type = 'auth'声明自己属于认证类插件,并设置了priority = 2500的高优先级,确保它在请求生命周期中尽早执行(apisix/plugins/key-auth.lua):

local _M = { version = 0.1, priority = 2500, type = 'auth', name = plugin_name, schema = schema, consumer_schema = consumer_schema, }

它只实现了一个核心钩子rewrite(apisix/plugins/key-auth.lua),在rewrite阶段完成 key 的提取、校验与 Consumer 绑定,工作流程如下:

  1. 提取 key:优先从conf.header指定的 Header 中读取;读取不到时,再从conf.query指定的 Query String 参数中读取。
  2. 缺失拦截:两处都取不到 key,直接返回401,响应体为{"message":"Missing API key in request"}
  3. 匹配 Consumer:通过consumer_mod.plugin(plugin_name)获取注册了key-auth的所有 Consumer 配置,再以key为键建立哈希映射(consumers_kv),用请求中的 key 精确匹配。
  4. 校验失败拦截:匹配不到 Consumer 时返回401,响应体为{"message":"Invalid API key in request"}
  5. 隐藏凭据(可选):若hide_credentialstrue,根据 key 的来源(Header 或 Query String)将其从请求中移除,避免认证信息透传给上游。
  6. 绑定 Consumer:调用consumer_mod.attach_consumer(ctx, consumer, consumer_conf),将匹配到的 Consumer 信息挂载到请求上下文,供后续插件(如consumer-restriction、限流限频插件)消费。

属性详解

key-auth的属性分为Consumer 端Router(Route/Service)端两组,前者定义密钥本身,后者定义密钥的获取方式与传递行为。

Consumer 端属性

名称类型必选项描述
keystring不同的 Consumer 应有不同的key,它应当是唯一的。如果多个 Consumer 使用了相同的key,将会出现请求匹配异常。该字段支持使用 APISIX Secret 资源,将值保存在 Secret Manager 中。

Consumer 端的 schema 同时声明了encrypt_fields = {"key"}(apisix/plugins/key-auth.lua),意味着该字段在开启数据加密后会被加密存储在 etcd 中,具体机制见下文「加密存储」小节。

关于key的唯一性,源码中建立了consumers[key]的哈希索引(apisix/plugins/key-auth.lua),后写入的同名 key 会覆盖先前的映射,这正是文档强调「多个 Consumer 使用相同 key 会出现请求匹配异常」的原因。因此生产环境中务必保证每个 Consumer 的key全局唯一。

Router 端属性

名称类型必选项默认值描述
headerstringapikey设置我们从哪个 header 获取 key。
querystringapikey设置我们从哪个 query string 获取 key,优先级低于header
hide_credentialsboolfalse当设置为false时将含有认证信息的 header 或 query string 传递给 Upstream。如果为true时将删除对应的 header 或 query string,具体删除哪一个取决于是从 header 获取 key 还是从 query string 获取 key。

以上默认值在 schema 定义 中均有体现:headerquery默认为"apikey"hide_credentials默认为false

需要注意的是header 优先于 query:只有当 header 中取不到 key 时,插件才会尝试从 query string 获取(apisix/plugins/key-auth.lua)。若两个来源同时携带 key,实际生效的是 header 中的值,hide_credentials也只会删除实际被使用的那一个来源,测试用例 TEST 19 与 TEST 23 专门验证了这一行为(t/plugin/key-auth.t)。

启用插件:创建 Consumer 与配置 Route

启用key-auth需要两步:先创建携带唯一 key 的 Consumer,再在 Route 上挂载插件。以下命令均通过 Admin API 完成,使用前请先从 conf/config.yaml 中取出admin_key并写入环境变量:

admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')

注意:config.yamladmin_key默认可能为空字符串,此时 APISIX 会自动生成随机 token 并回写配置文件;生产环境强烈建议使用外部机制生成并保管该 token(见 conf/config.yaml 的注释说明)。

第一步:创建 Consumer

curl http://127.0.0.1:9180/apisix/admin/consumers \ -H "X-API-KEY: $admin_key" -X PUT -d ' { "username": "jack", "plugins": { "key-auth": { "key": "auth-one" } } }'

该请求向 Admin API 注册了一个用户名为jack的 Consumer,其key-auth插件的密钥为auth-one。此操作也可通过 APISIX Dashboard 的 Web 界面完成,在 Consumer 页面创建消费者并添加key-auth插件即可。

第二步:创建 Route 并挂载插件

curl http://127.0.0.1:9180/apisix/admin/routes/1 \ -H "X-API-KEY: $admin_key" -X PUT -d ' { "methods": ["GET"], "uri": "/index.html", "id": 1, "plugins": { "key-auth": {} }, "upstream": { "type": "roundrobin", "nodes": { "127.0.0.1:1980": 1 } } }'

Route 上使用空的"key-auth": {}即表示启用插件并全部使用默认配置(header 与 query 均为apikey)。此时访问/index.html的 GET 请求必须携带有效的apikey才能通过网关。

自定义 Header 名称

如果你不想从默认的apikeyheader 获取 key,可以在插件配置中自定义 header,例如使用更常见的Authorization

{ "key-auth": { "header": "Authorization" } }

测试用例 TEST 10 / TEST 11 验证了自定义 header 后,请求Authorization: auth-one能正常通过(t/plugin/key-auth.t)。同理,也可以通过"query": "auth"自定义 query 参数名,随后以GET /hello?auth=auth-one访问(TEST 12 / TEST 13)。

测试插件:验证三种典型场景

插件配置完成后,可通过以下命令验证认证行为。

场景一:携带正确的 key,放行

curl http://127.0.0.2:9080/index.html -H 'apikey: auth-one' -i
HTTP/1.1 200 OK ...

场景二:未携带 key,返回 401

curl http://127.0.0.2:9080/index.html -i
HTTP/1.1 401 Unauthorized ... {"message":"Missing API key in request"}

场景三:key 错误,返回 401

curl http://127.0.0.2:9080/index.html -H 'apikey: abcabcabc' -i
HTTP/1.1 401 Unauthorized ... {"message":"Invalid API key in request"}

这三种场景与单元测试中 TEST 5(valid consumer)、TEST 6(invalid consumer)、TEST 7(not found apikey header)一一对应(t/plugin/key-auth.t),错误响应的 message 文本也与源码中的返回值完全一致,可直接作为排障时的对照依据。

关于 401 的补充说明

在 HTTP 规范中,401 Unauthorized通常要求配合WWW-Authenticate响应头使用。key-auth插件直接返回401而没有附加该头,因此在实践中若客户端(如部分浏览器或 SDK)依赖WWW-Authenticate触发认证流程,需结合response-rewrite插件或业务侧逻辑自行补充。这一行为并未在当前仓库的插件实现中体现,使用前应结合自身客户端兼容性进行评估。

hide_credentials:控制认证信息是否透传上游

hide_credentials用于决定认证信息(Header 或 Query String 中的 key)是否继续传递给 Upstream:

  • false(默认):含有认证信息的 header 或 query string 原样传递给 Upstream。测试用例 TEST 15 验证了hide_credentials=false时,上游能收到apikey: auth-one请求头(t/plugin/key-auth.t)。
  • true:删除对应的 header 或 query string。删除的目标取决于 key 实际来自何处——从 header 取到就删 header,从 query 取到就删 query,且只删除被使用的那一个来源,不会误删其他同名无关参数。

底层实现在 apisix/plugins/key-auth.lua:通过core.request.set_header(ctx, conf.header, nil)删除 header,或通过core.request.set_uri_args移除 query 参数。

相关测试覆盖了各种组合(t/plugin/key-auth.t):

测试用例场景预期行为
TEST 17header 携带 key,hide_credentials=true上游请求头中无apikey
TEST 18header 携带 key 与无关头test仅删除apikey,保留test
TEST 19header 与 query 同时携带 key删除 header,query 参数保留
TEST 21query 携带 key,hide_credentials=true上游 query 参数中无auth
TEST 23header 与 query 同时携带 key(自定义auth删除 query,header 保留

生产实践建议:如果上游业务不需要感知调用方身份,应将hide_credentials设为true,避免 API Key 泄露给后端服务或第三方日志系统。

集成 APISIX Secret:将密钥托管给外部密钥管理服务

Consumer 端的key字段支持 APISIX Secret 引用,可将明文密钥从配置中抽离,存放到环境变量或 HashiCorp Vault 等密钥管理服务中。APISIX Secret 的目标是确保密钥在整个平台中不以明文形式存在(docs/zh/latest/terminology/secret.md)。

从源码看,key-auth的密钥解析发生在 Consumer 缓存构建阶段:create_consume_cache会调用secret.fetch_secretsauth_conf中的 Secret 引用解析为真实值后,再以 key 建立索引(apisix/consumer.lua),这意味着 Secret 解析结果带有缓存,密钥轮换后需要等待缓存过期(默认 TTL 300 秒)或触发配置版本更新才会生效。

使用环境变量引用密钥

curl http://127.0.0.1:9180/apisix/admin/consumers \ -H "X-API-KEY: $admin_key" -X PUT -d ' { "username": "jack", "plugins": { "key-auth": { "key": "$env://test_auth" } } }'

对应测试用例 TEST 26 / TEST 27 使用env test_auth=authone;声明环境变量后,请求GET /hello?auth=authone验证通过(t/plugin/key-auth.t)。引用格式为$ENV://$env_name/$sub_key,支持系统环境变量与 Nginxenv指令配置的变量。

使用 HashiCorp Vault 引用密钥

先创建 Vault 资源配置,再在 Consumer 中引用:

curl http://127.0.0.1:9180/apisix/admin/secrets/vault/test1 \ -H "X-API-KEY: $admin_key" -X PUT -d ' { "uri": "http://127.0.0.1:8200", "prefix": "kv/apisix", "token": "root" }'
curl http://127.0.0.1:9180/apisix/admin/consumers \ -H "X-API-KEY: $admin_key" -X PUT -d ' { "username": "jack", "plugins": { "key-auth": { "key": "$secret://vault/test1/jack/key" } } }'

测试用例 TEST 28 ~ TEST 32 完整演示了「创建 Vault 资源 → 写入kv/apisix/jack中的key=authtwo→ 以$secret://vault/test1/jack/key引用 → 用authtwo请求验证通过」的全链路(t/plugin/key-auth.t)。Vault 的 token 本身也支持通过$ENV://VAULT_TOKEN引用,避免明文写入配置。

密钥加密存储:encrypt_fields 与 data_encryption

key-auth的 Consumer schema 声明了encrypt_fields = {"key"}(apisix/plugins/key-auth.lua),表示该字段支持加密存储。开启后:

  • 通过 Admin API 新增或更新资源时,key会被自动加密后存入 etcd;
  • 通过 Admin API 读取资源,以及插件运行时,APISIX 会自动解密使用。

该能力需要 APISIX 版本不小于 3.1,并在 conf/config.yaml 中开启data_encryption配置:

apisix: data_encryption: enable: true keyring: - edd1c9f0985e76a2 - qeddd145sfvddff4

keyring是一个数组,可配置多个密钥;APISIX 会按顺序依次尝试用 keyring 中的密钥解密数据,失败则尝试下一个,直到成功(docs/zh/latest/plugin-develop.md)。enable_encrypt_fields默认开启(测试文件通过yaml_config显式关闭以验证非加密路径),生产环境建议保持开启并妥善保管keyring

加密存储对key-auth的价值在于:即使 etcd 中的数据被窃取,攻击者看到的也只是密文,无法直接获取 API Key 明文。

删除插件

需要禁用key-auth时,通过 Admin API 将 Route 配置中的plugins置空,APISIX 会自动重新加载相关配置,无需重启服务:

curl http://127.0.0.1:9180/apisix/admin/routes/1 \ -H "X-API-KEY: $admin_key" -X PUT -d ' { "methods": ["GET"], "uri": "/index.html", "id": 1, "plugins": { }, "upstream": { "type": "roundrobin", "nodes": { "127.0.0.1:1980": 1 } } }'

删除后该 Route 上的请求将不再进行 key 校验,直接转发至上游。需要注意的是,删除 Route 上的插件并不会删除 Consumer 上的key-auth配置,如需彻底移除,还需另行更新或删除对应的 Consumer 资源。

与其它认证插件的取舍

key-auth属于 APISIX 认证插件家族(type = 'auth')中的轻量级方案,与basic-authjwt-authhmac-authkeycloakopenid-connect等并列。它适用于对安全性要求适中、希望以最小成本快速接入的场景(如内部服务间调用、简单移动端 API);若需要防重放、请求签名、短期令牌或对接 OIDC 等企业身份体系,则应评估hmac-authjwt-authopenid-connect等方案。

由于key-auth的 key 是长期有效的静态凭据,且明文随请求传输(除非配合 HTTPS),请务必:

  • 全程使用 HTTPS 传输,避免 key 在链路上被截获;
  • 为每个调用方分配独立且唯一的 key,便于审计与单独吊销;
  • 结合 consumer-restriction 插件 对已认证 Consumer 做进一步的访问控制;
  • 定期轮换 key,并结合上文介绍的 Secret 引用与加密存储,减少明文暴露面。

参考资源

  • 插件官方文档:docs/zh/latest/plugins/key-auth.md
  • 插件源码实现:apisix/plugins/key-auth.lua
  • Consumer 机制与密钥解析:apisix/consumer.lua
  • 单元测试(32 个用例,覆盖 schema、自定义 header/query、hide_credentials、Secret 引用等):t/plugin/key-auth.t
  • Consumer 概念:docs/zh/latest/terminology/consumer.md
  • Secret 概念与使用:docs/zh/latest/terminology/secret.md
  • 加密存储字段规范:docs/zh/latest/plugin-develop.md
  • Admin API 密钥配置:conf/config.yaml

【免费下载链接】apisixThe Cloud-Native API Gateway项目地址: https://gitcode.com/GitHub_Trending/ap/apisix

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询