OpenResty网关JWT鉴权核心是前置到access_by_lua*阶段,关键在判得准、退得快、配得稳:一用verify_jwt_obj精准校验声明与算法;二统一密钥base64编解码;三白名单跳过登录等路径;四精准配置lua_package_path及模块加载。

OpenResty 在网关层做 JWT 鉴权,核心是把验证逻辑前置到 access_by_lua* 阶段,避免无效请求触达后端。高效的关键不在于“写得多”,而在于“判得准、退得快、配得稳”。下面从四个实际落地要点展开:
一、用对验证方式:优先用 jwt:verify_jwt_obj 而非 jwt:verify
新版 lua-resty-jwt(v0.3.0+)推荐使用 verify_jwt_obj 方法,它支持声明校验(如 exp、iss、nbf)、算法指定和错误结构化返回,比旧版 verify 更严谨。
- 必须显式传入
secret和algorithm,例如HS256,避免默认行为引发兼容问题 - 启用自动过期检查:
{ secret = "xxx", algorithm = "HS256", verify_exp = true } - 失败时返回带
reason字段的 table,便于日志定位,比如"token is expired"或"signature mismatch"
二、密钥处理要一致:注意 base64 编解码对齐
JWT 签名密钥在不同语言中处理方式常不一致——Java 后端可能用 Base64.getDecoder().decode() 解码原始密钥字符串,而 Lua 默认按原样使用。若不统一,必报 signature mismatch。
- 先确认后端生成 token 时对密钥做了什么操作(是否 decode?是否补位?)
- Lua 中对应处理:若后端 decode 过,就用
ngx.decode_base64(secret);若后端用的是原始 ASCII 密钥,Lua 直接传字符串即可 - 密钥建议用 32 字节以上随机字符串(如
openssl rand -base64 32生成),避免弱密钥导致签名易伪造
三、跳过鉴权路径要预判,别让 Lua 做无谓解析
登录、注册、健康检查等接口本就不该走 JWT 验证。把这些路径提前判断并放行,能显著降低 CPU 开销(尤其高 QPS 场景)。
- 用 Lua table 定义白名单,例如:
local no_auth_paths = {"/api/login", "/api/register", "/healthz"} - 用
string.match(ngx.var.request_uri, "^/api/login.*")或简单前缀匹配,比正则更轻量 - 匹配成功直接
return,不执行后续 token 提取与验证逻辑
四、Nginx 配置与模块加载必须精准
脚本写得再好,加载错路径或漏依赖也会失败。关键配置不能靠猜:
-
lua_package_path必须包含resty模块所在路径,例如:/usr/local/openresty/lualib/?.lua;/usr/local/openresty/lualib/resty/?.lua;; - 确保已安装
lua-resty-jwt及其依赖(lua-resty-hmac、lua-resty-string),推荐用opm get SkyLothar/lua-resty-jwt - 验证逻辑放在
access_by_lua_file(而非content_by_lua_file),保证在代理转发前拦截 - 出错时用
ngx.exit(ngx.HTTP_UNAUTHORIZED)终止流程,不拼 HTML 或重定向,保持响应轻量


















