APISIX 网关如何实现验签

avatar
@海尔优家智能科技(北京)有限公司

在 APISIX(云原生 API 网关)中实现接口验签逻辑,核心是通过其插件机制完成 —— 利用 APISIX 内置的验签相关插件(如hmac-authjwt-auth)或自定义 Lua 插件,拦截请求并执行签名验证流程,确保请求来源合法、数据未被篡改。

1. APISIX 验签的核心原理

APISIX 的请求处理流程为:请求进入 → 插件执行(顺序可配置) → 转发至上游服务。验签逻辑本质是在插件执行阶段,通过以下步骤实现:

  1. 提取 签名 相关参数:从请求头(如X-SignatureAuthorization)、请求参数或 Body 中,提取签名值、时间戳、随机串、AccessKey 等验签必需信息。
  2. 生成待验签串:按照业务约定的规则(如 “参数按 ASCII 排序 + 拼接时间戳 + 密钥”),重组请求中的关键数据(如请求参数、Body、时间戳),生成 “待验签字符串”。
  3. 执行 签名 验证:使用与客户端约定的算法(如 HMAC-SHA256、RSA),结合预设的密钥(或公钥)对 “待验签串” 进行签名,对比生成的签名与请求中提取的签名是否一致。
  4. 拦截或放行:验证通过则继续转发请求至上游;验证失败(如签名不匹配、时间戳过期)则直接返回 401/403 错误,拦截请求。

2. APISIX 实现验签的 3 种常见方式

根据业务场景(如是否需要自定义验签规则、签名算法类型),APISIX 提供了 “内置插件”“自定义 Lua 插件”“集成外部服务” 三种实现方式,以下详细说明:

方式 1:使用 APISIX 内置验签插件(推荐,无需编码)

APISIX 提供了多个成熟的内置插件,覆盖主流验签场景(如 HMAC 对称加密、JWT 令牌、Basic Auth),无需编写代码,仅需通过配置即可启用。

1.1 HMAC 对称加密验签(hmac-auth插件)

适用于客户端与 网关 共享 密钥的场景(如内部服务间调用),基于 HMAC 算法(如 HMAC-SHA256)验证签名,支持防重放(通过时间戳 + nonce)。

核心配置步骤:

(1)创建 Consumer(消费者,即客户端身份) 为每个客户端配置唯一的access_key(标识客户端)和secret_key(对称密钥,需客户端与网关一致),并绑定hmac-auth插件。示例(通过 APISIX Admin API 配置):

# 创建Consumer并启用hmac-auth插件curl http://apisix-admin:9180/apisix/admin/consumers -X PUT -d '
{
  "username": "client_001",  # Consumer名称(自定义)
  "plugins": {
    "hmac-auth": {
      "access_key": "AK123456",  # 客户端唯一标识(客户端需携带)
      "secret_key": "SKabcdef123456",  # 对称密钥(客户端与网关共享,需保密)
      "sign_header": "X-HMAC-Signature",  # 请求头中签名的字段名
      "clock_skew": 300,  # 允许的时间戳偏差(秒,防重放)
      "nonce_header": "X-HMAC-Nonce",  # 请求头中随机串的字段名
      "timestamp_header": "X-HMAC-Timestamp"  # 请求头中时间戳的字段名
    }
  }
}'

(2)为 Route/ Service 绑定 hmac-auth 插件将插件应用到需要验签的路由(Route)或服务(Service),确保该路由的所有请求都必须通过 HMAC 验签。示例(为 Route 配置):

# 为Route 1绑定hmac-auth插件curl http://apisix-admin:9180/apisix/admin/routes/1 -X PUT -d '
{
  "uri": "/api/v1/order/*",  # 需验签的接口路径
  "upstream": {
    "type": "roundrobin",
    "nodes": {"192.168.1.100:8080": 1}  # 上游服务地址
  },
  "plugins": {
    "hmac-auth": {}  # 启用插件(无需额外配置,复用Consumer的插件参数)
  }
}'

(3)客户端请求示例

  客户端需按以下规则生成签名并携带请求头:

  • 生成nonce(随机串,如abc123)、timestamp(当前时间戳,如1690000000);
  • 待验签串规则:method + uri + timestamp + nonce + body(具体规则可通过插件参数sign_params自定义);
  • 使用secret_key对 “待验签串” 进行 HMAC-SHA256 加密,得到签名值;
  • 请求头携带:X-HMAC-AccessKey: AK123456X-HMAC-Timestamp: 1690000000X-HMAC-Nonce: abc123X-HMAC-Signature: 签名值

1.2 JWT 令牌验签(jwt-auth插件)

适用于分布式 系统、用户认证场景,客户端先通过登录接口获取 JWT 令牌,后续请求携带令牌,网关通过公钥验证令牌有效性(支持对称 / 非对称加密)。

核心配置步骤:

(1)创建 Consumer 并配置 JWT 参数示例(对称加密,使用secret验证;非对称加密需配置public_key):

curl http://apisix-admin:9180/apisix/admin/consumers -X PUT -d '
{
  "username": "user_001",
  "plugins": {
    "jwt-auth": {
      "secret": "jwt_secret_123",  # 对称密钥(非对称加密用public_key替代)
      "algorithm": "HS256",  # 算法(HS256=对称,RS256=非对称)
      "exp": 3600,  # 令牌过期时间(秒)
      "token_header": "Authorization",  # 携带令牌的请求头(如Bearer Token)
      "token_prefix": "Bearer "  # 令牌前缀(如"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...")
    }
  }
}'

(2)为 Route 绑定 jwt-auth 插件确保请求需携带有效 JWT 令牌才能访问:

curl http://apisix-admin:9180/apisix/admin/routes/2 -X PUT -d '
{
  "uri": "/api/v1/user/*",
  "upstream": {"nodes": {"192.168.1.101:8080": 1}},
  "plugins": {"jwt-auth": {}}
}'

(3)客户端请求示例

  • 登录获取 JWT 令牌:客户端通过登录接口(如/login)提交账号密码,上游服务生成 JWT 令牌(使用secret签名)返回给客户端;
  • 后续请求携带令牌:请求头添加Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...,APISIX 验证令牌签名及过期时间。

方式 2:自定义 Lua 插件(适合复杂自定义验签规则)

若内置插件无法满足业务需求(如特殊签名算法、复杂验签逻辑),可基于 APISIX 的Lua 插件开发框架编写自定义验签插件,完全控制验签流程。

核心开发步骤:

(1)创建插件目录与文件APISIX 插件默认存放在/usr/local/apisix/plugins/目录,新建自定义插件文件(如custom-sign.lua)。

(2)编写插件核心逻辑插件需实现rewrite(请求转发前执行)或access(权限校验阶段)方法,在方法中编写验签逻辑。示例(自定义 HMAC 验签插件核心代码):

local core = require("apisix.core")local hmac = require("resty.hmac")-- 插件Schema(定义配置参数,如secret_key、sign_header)local schema = {
  type = "object",
  properties = {
    secret_key = {type = "string"},  -- 对称密钥
    sign_header = {type = "string", default = "X-Custom-Sign"},  -- 签名请求头
    timestamp_header = {type = "string", default = "X-Custom-Timestamp"}  -- 时间戳请求头},
  required = {"secret_key"}}-- 插件主逻辑(access阶段执行)local function access(conf, ctx)-- 1. 提取请求中的验签参数local req_sign = core.request.header(ctx, conf.sign_header)local req_timestamp = core.request.header(ctx, conf.timestamp_header)local req_method = core.request.get_method(ctx)local req_uri = ctx.var.uri
  local req_body = core.request.get_body(ctx)  -- 需开启body读取(在APISIX配置中设置)-- 2. 校验必要参数是否存在if not req_sign or not req_timestamp thenreturn 401, {message = "missing sign or timestamp"}end-- 3. 校验时间戳(防重放,允许5分钟偏差)local current_ts = ngx.time()if math.abs(current_ts - tonumber(req_timestamp)) > 300 thenreturn 401, {message = "timestamp expired"}end-- 4. 生成待验签串(按业务规则拼接)local sign_str = string.format("%s%s%s%s", req_method, req_uri, req_timestamp, req_body or "")-- 5. 计算HMAC签名并对比local hmac_obj = hmac:new(conf.secret_key, hmac.ALGOS.SHA256)local computed_sign = hmac_obj:final(sign_str, true)  -- true表示返回hex格式if computed_sign ~= req_sign thenreturn 403, {message = "invalid signature"}end-- 6. 验签通过,继续转发请求returnend-- 注册插件return {
  version = 0.1,
  priority = 2000,  -- 插件执行优先级(数值越大越先执行)
  name = "custom-sign",  -- 插件名称
  schema = schema,
  access = access  -- 绑定access阶段执行}

(3)启用自定义插件

  • 在 APISIX 配置文件(config.yaml)中添加插件到plugins列表,确保 APISIX 加载插件:
plugins:
  - custom-sign  # 添加自定义插件名称
  - hmac-auth
  - jwt-auth
  • 重启 APISIX:apisix restart
  • 为 Consumer 和 Route 绑定custom-sign插件(同内置插件配置方式)。

方式 3:集成外部验签服务(适合验签逻辑独立部署)

若验签逻辑复杂(如依赖数据库查询密钥、多系统共享验签服务),可通过 APISIX 的ext-plugin(外部插件)或http-logger+request-validator,将验签请求转发到外部服务(如 Java/Python 编写的验签服务),由外部服务返回验签结果,APISIX 根据结果决定是否放行。

核心实现思路:

(1)部署外部验签服务

开发一个验签 API(如http://sign-service:8080/verify),接收 APISIX 转发的请求参数(如请求头、Body、路径),执行验签逻辑,返回{"success": true/false, "message": "..."}

(2)APISIX 配置转发与结果判断使用ext-pluginpre-req(请求前调用外部服务)功能,或通过proxy-rewrite将请求转发到验签服务,再通过response-rewrite判断结果:

# 示例:为Route配置外部验签服务curl http://apisix-admin:9180/apisix/admin/routes/3 -X PUT -d '
{
  "uri": "/api/v1/pay/*",
  "plugins": {
    "ext-plugin-pre-req": {
      "conf": [
        {
          "name": "ext-plugin-http",  # 调用外部HTTP服务的插件
          "value": '{"uri":"http://sign-service:8080/verify","method":"POST","timeout":500}'
        }
      ]
    }
  },
  "upstream": {"nodes": {"192.168.1.102:8080": 1}}
}'

外部验签服务返回success: false时,APISIX 直接拦截请求并返回错误。

3. 验签配置的最佳实践

  1. 密钥管理

    1. 对称密钥(如hmac-authsecret_key)需通过 APISIX 的配置中心(如 etcd、Nacos)管理,避免硬编码;
    2. 非对称加密(如 JWT RS256)需定期轮换公钥 / 私钥,确保密钥安全。
  2. 防重放攻击

    1. 必须加入 “时间戳 + nonce” 机制(如hmac-authclock_skewnonce_header),防止攻击者复用旧签名;
    2. 可通过 APISIX 的redis插件缓存已使用的nonce,避免重复使用。
  3. 性能优化

    1. 自定义插件中避免频繁 IO 操作(如数据库查询),可将密钥缓存到 APISIX 本地(如core.lrucache);
    2. 对于大 Body 请求,验签时可仅对 Body 的哈希值(如 MD5)进行签名,减少数据处理量。
  4. 日志与监控

    1. 启用 APISIX 的error-log-loggeraccess-logger,记录验签失败日志(如签名不匹配、时间戳过期);
    2. 通过 APISIX 的监控插件(如prometheus)统计验签成功率,及时发现异常请求。

4. 常见问题排查

  1. 验签失败但客户端确认 签名 正确

    1. 检查 “待验签串” 的拼接规则是否与客户端一致(如参数排序、是否包含 Body、大小写敏感);
    2. 确认 APISIX 是否正确读取请求 Body(需在config.yaml中设置proxy_body_temp_path,并确保插件启用 Body 读取)。
  2. JWT 令牌验证失败

    1. 检查algorithm是否匹配(如客户端用 HS256,网关配置 RS256);
    2. 确认令牌未过期(exp字段),且secret/public_key与客户端签名时使用的密钥一致。
  3. 自定义插件不生效

    1. 检查插件是否添加到 APISIX 的plugins列表中;
    2. 通过 APISIX 日志(/usr/local/apisix/logs/error.log)查看插件执行报错信息。

5.团队介绍

智慧家技术平台-应用软件框架开发」主要负责设计工具的研发,包括营销设计工具、家电VR设计和展示、水电暖通前置设计能力,研发并沉淀素材库,构建家居家装素材库,集成户型库、全品类产品库、设计方案库、生产工艺模型,打造基于户型和风格的AI设计能力,快速生成算量和报价;同时研发了门店设计师中心和项目中心,包括设计师管理能力和项目经理管理能力。实现了场景全生命周期管理,同时为水,空气,厨房等产业提供商机管理工具,从而实现了以场景贯穿的B端C端全流程系统。