# 怎么使用Nginx和Lua進行JWT校驗
## 前言
在現代Web開發中,JSON Web Token (JWT) 已成為實現身份驗證和授權的流行方案。當我們需要在Nginx層面實現統一的JWT校驗時,結合Lua腳本的能力可以構建高效、靈活的解決方案。本文將詳細介紹如何利用Nginx和Lua實現JWT校驗的全過程。
## 一、基礎概念
### 1.1 JWT簡介
JWT(JSON Web Token)是一種開放標準(RFC 7519),用于在各方之間安全地傳輸信息作為JSON對象。它由三部分組成:
- **Header**:包含令牌類型和簽名算法
- **Payload**:包含聲明(用戶信息和其他數據)
- **Signature**:用于驗證消息完整性
典型JWT格式:`xxxxx.yyyyy.zzzzz`
### 1.2 Nginx與Lua
Nginx作為高性能Web服務器,通過`ngx_http_lua_module`模塊支持Lua腳本執行。這種組合允許我們在請求處理的不同階段插入自定義邏輯,特別適合實現認證、流量控制等功能。
## 二、環境準備
### 2.1 安裝必要組件
```bash
# 安裝OpenResty(包含Nginx和LuaJIT)
wget https://openresty.org/package/centos/openresty.repo
sudo mv openresty.repo /etc/yum.repos.d/
sudo yum install -y openresty
# 安裝LuaJWT庫
sudo opm get cdbattags/lua-resty-jwt
location /lua-test {
content_by_lua_block {
ngx.say("Lua module is working!")
}
}
訪問該端點應返回預期文本。
創建/etc/nginx/conf.d/jwt-verify.lua
:
local jwt = require("resty.jwt")
local validators = require("resty.jwt-validators")
local _M = {}
-- 配置JWT密鑰和算法
local secret = "your-256-bit-secret"
local algorithm = "HS256"
-- 必驗證的聲明
local required_claims = {
"exp",
"iat",
-- 添加其他必要聲明
}
function _M.verify()
-- 從Header獲取Token
local auth_header = ngx.var.http_Authorization
if not auth_header then
return false, "Missing Authorization header"
end
-- 提取Bearer Token
local _, _, token = string.find(auth_header, "Bearer%s+(.+)")
if not token then
return false, "Invalid Authorization header format"
end
-- 解碼并驗證JWT
local jwt_obj = jwt:verify(secret, token)
if not jwt_obj.verified then
return false, "Invalid token: " .. jwt_obj.reason
end
-- 驗證聲明
for _, claim in ipairs(required_claims) do
if jwt_obj.payload[claim] == nil then
return false, "Missing required claim: " .. claim
end
end
-- 驗證過期時間
local claim_spec = {
exp = validators.is_not_expired()
}
local valid, errors = validators.verify_claims(jwt_obj.payload, claim_spec)
if not valid then
return false, "Invalid claims: " .. table.concat(errors, ", ")
end
-- 將payload傳遞給后續處理
ngx.ctx.jwt_payload = jwt_obj.payload
return true, "Token is valid"
end
return _M
在Nginx配置中引入Lua腳本:
http {
lua_package_path "/etc/nginx/conf.d/?.lua;;";
server {
listen 80;
location /api {
access_by_lua_block {
local jwt = require("jwt-verify")
local ok, err = jwt.verify()
if not ok then
ngx.status = ngx.HTTP_UNAUTHORIZED
ngx.say(err)
return ngx.exit(ngx.HTTP_UNAUTHORIZED)
end
}
proxy_pass http://backend;
}
}
}
實際生產環境中,密鑰可能需要動態獲?。?/p>
local function get_secret(kid)
-- 從數據庫或緩存獲取密鑰
local redis = require "resty.redis"
local red = redis:new()
local ok, err = red:connect("redis-host", 6379)
if not ok then
return nil, "Failed to connect to Redis"
end
local secret, err = red:get("jwt:secret:" .. kid)
if not secret then
return nil, "Key not found"
end
return secret
end
function _M.verify()
-- ... 獲取token邏輯不變
-- 從payload提取租戶信息
local tenant = jwt_obj.payload.tenant
if not tenant then
return false, "Missing tenant information"
end
-- 根據租戶獲取對應密鑰
local tenant_secret = get_tenant_secret(tenant)
if not tenant_secret then
return false, "Invalid tenant"
end
-- 使用租戶特定密鑰驗證
jwt_obj = jwt:verify(tenant_secret, token)
-- ... 后續驗證不變
end
local lrucache = require "resty.lrucache"
local cache = lrucache.new(1000) -- 緩存1000個條目
function _M.verify()
-- ... 獲取token
-- 檢查緩存
local cached = cache:get(token)
if cached then
ngx.ctx.jwt_payload = cached
return true, "Token is valid (cached)"
end
-- ... 驗證邏輯
-- 驗證通過后緩存
cache:set(token, jwt_obj.payload, 300) -- 緩存5分鐘
end
wrk
進行壓力測試密鑰管理:
Token處理:
防御措施:
使用curl
進行測試:
# 有效請求
curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." http://localhost/api
# 無效請求
curl -H "Authorization: Bearer invalid.token.here" http://localhost/api
創建test_jwt.lua
:
local jwt = require("resty.jwt")
local test = require("resty.test")
describe("JWT驗證測試", function()
it("應拒絕無效Token", function()
local ok, err = verify_jwt("invalid.token")
assert.is_false(ok)
end)
it("應接受有效Token", function()
local token = generate_valid_token()
local ok, err = verify_jwt(token)
assert.is_true(ok)
end)
end)
Lua模塊未加載:
lua_package_path
JWT驗證失敗:
性能問題:
-- 啟用調試日志
ngx.log(ngx.ERR, "Debug info: ", require("cjson").encode(jwt_obj))
方案 | 優點 | 缺點 |
---|---|---|
Nginx + Lua | 高性能,低延遲 | 需要維護Lua代碼 |
API網關 | 功能全面 | 額外基礎設施 |
應用層校驗 | 靈活控制 | 性能開銷大 |
通過Nginx和Lua實現JWT校驗提供了高性能、低延遲的認證解決方案。本文介紹了從基礎實現到高級優化的完整流程,實際部署時請根據具體需求調整安全配置和性能參數。這種方案特別適合需要統一認證層的高流量系統。
”`
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。