在 APISIX(云原生 API 网关)中实现接口验签逻辑,核心是通过其插件机制完成 —— 利用 APISIX 内置的验签相关插件(如hmac-auth、jwt-auth)或自定义 Lua 插件,拦截请求并执行签名验证流程,确保请求来源合法、数据未被篡改。
1. APISIX 验签的核心原理
APISIX 的请求处理流程为:请求进入 → 插件执行(顺序可配置) → 转发至上游服务。验签逻辑本质是在插件执行阶段,通过以下步骤实现:
- 提取 签名 相关参数:从请求头(如
X-Signature、Authorization)、请求参数或 Body 中,提取签名值、时间戳、随机串、AccessKey 等验签必需信息。 - 生成待验签串:按照业务约定的规则(如 “参数按 ASCII 排序 + 拼接时间戳 + 密钥”),重组请求中的关键数据(如请求参数、Body、时间戳),生成 “待验签字符串”。
- 执行 签名 验证:使用与客户端约定的算法(如 HMAC-SHA256、RSA),结合预设的密钥(或公钥)对 “待验签串” 进行签名,对比生成的签名与请求中提取的签名是否一致。
- 拦截或放行:验证通过则继续转发请求至上游;验证失败(如签名不匹配、时间戳过期)则直接返回 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: AK123456、X-HMAC-Timestamp: 1690000000、X-HMAC-Nonce: abc123、X-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-plugin的pre-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. 验签配置的最佳实践
-
密钥管理
- 对称密钥(如
hmac-auth的secret_key)需通过 APISIX 的配置中心(如 etcd、Nacos)管理,避免硬编码; - 非对称加密(如 JWT RS256)需定期轮换公钥 / 私钥,确保密钥安全。
- 对称密钥(如
-
防重放攻击
- 必须加入 “时间戳 + nonce” 机制(如
hmac-auth的clock_skew和nonce_header),防止攻击者复用旧签名; - 可通过 APISIX 的
redis插件缓存已使用的nonce,避免重复使用。
- 必须加入 “时间戳 + nonce” 机制(如
-
性能优化
- 自定义插件中避免频繁 IO 操作(如数据库查询),可将密钥缓存到 APISIX 本地(如
core.lrucache); - 对于大 Body 请求,验签时可仅对 Body 的哈希值(如 MD5)进行签名,减少数据处理量。
- 自定义插件中避免频繁 IO 操作(如数据库查询),可将密钥缓存到 APISIX 本地(如
-
日志与监控
- 启用 APISIX 的
error-log-logger和access-logger,记录验签失败日志(如签名不匹配、时间戳过期); - 通过 APISIX 的监控插件(如
prometheus)统计验签成功率,及时发现异常请求。
- 启用 APISIX 的
4. 常见问题排查
-
验签失败但客户端确认 签名 正确
- 检查 “待验签串” 的拼接规则是否与客户端一致(如参数排序、是否包含 Body、大小写敏感);
- 确认 APISIX 是否正确读取请求 Body(需在
config.yaml中设置proxy_body_temp_path,并确保插件启用 Body 读取)。
-
JWT 令牌验证失败
- 检查
algorithm是否匹配(如客户端用 HS256,网关配置 RS256); - 确认令牌未过期(
exp字段),且secret/public_key与客户端签名时使用的密钥一致。
- 检查
-
自定义插件不生效
- 检查插件是否添加到 APISIX 的
plugins列表中; - 通过 APISIX 日志(
/usr/local/apisix/logs/error.log)查看插件执行报错信息。
- 检查插件是否添加到 APISIX 的
5.团队介绍
「智慧家技术平台-应用软件框架开发」主要负责设计工具的研发,包括营销设计工具、家电VR设计和展示、水电暖通前置设计能力,研发并沉淀素材库,构建家居家装素材库,集成户型库、全品类产品库、设计方案库、生产工艺模型,打造基于户型和风格的AI设计能力,快速生成算量和报价;同时研发了门店设计师中心和项目中心,包括设计师管理能力和项目经理管理能力。实现了场景全生命周期管理,同时为水,空气,厨房等产业提供商机管理工具,从而实现了以场景贯穿的B端C端全流程系统。