介绍
nginx与openresty是两种优秀知名的7层负载均衡软件,nginx以其出色的性能和稳定性成为首选,而openresty则是在Nginx基础上构建的,支持嵌入Lua语言,大幅提升了开发效率。
安装OpenResty
- 版本
openresty-1.25.3.1-win64 - 下载地址
点击跳转下载地址
功能实现
验签直接返回响应体
- 打开nginx.conf文件编写脚本(使用hmac对原文生成hash值再取base64编码)
server {
listen 80;
server_name localhost;
#对外接口验签
location /api {
default_type "application/json";
content_by_lua_block {
-- table是否包含指定元素方法
function arr_include(tab, value)
for k,v in pars(tab) do
if v == value then
return true
end
end
return false
end
local headers = ngx.req.get_headers();
local token = headers["token"];
-- 无token
if (token == nil) then
ngx.say(string.format("{\"success\":false,\"msg\":\"%s\"}", "token为空"));
return;
end
-- 黑名单
local guestIp = headers["X-Real-IP"] or headers["X-Forwarded-For"] or ngx.var.remote_addr;
ngx.say(string.format("请求ip:%s", guestIp));
local blacks = {"127.0.0.1", "10.190.75.139"};
if (arr_include(blacks, guestIp)) then
ngx.say(string.format("{\"success\":false,\"msg\":\"%s\"}", "黑名单禁止访问"));
return;
end
-- 验签-读取请求体
ngx.req.read_body();
local reqBody = ngx.req.get_body_data();
ngx.say(string.format("请求体:%s", reqBody));
-- 开始验签
local key = "A7409BB67B472E6CC7EF17C49784A6B8";
local digest = ngx.encode_base64(ngx.hmac_sha1(key, reqBody));
ngx.say(string.format("nginx签名值:%s", digest));
if (digest == token) then
ngx.say(string.format("{\"success\":true,\"msg\":\"%s\"}", "校验通过"));
else
ngx.say(string.format("{\"success\":false,\"msg\":\"%s\"}", "验签失败"));
end
}
}
}
-
启动nginx.exe
-
客户端hmac哈希签名
通过sha1哈希算法与密钥生成签名值
-
注释黑名单代码并且nginx -s reload后,调用接口测
-
启用黑名单代码后,调用接口测试
黑名单功能也可以将黑名单放入redis,通过OpenResty编写lua脚本从redis获取黑名单ip来实现
验签通过后转发到上游服务
- 介绍
在上面的例子实现了验签后直接返回结果,但真实应用的时候一般是验签通过后转发到上游的业务应用,这时候我们的脚本得稍微进行改造,使用access_by_lua_block。 - 代码实现
server {
listen 80;
server_name localhost;
location / {
default_type "text/html";
content_by_lua 'ngx.say("<html><p>nginx start by lua<p><html>")';
}
#对外接口验签
location /api {
default_type "application/json";
access_by_lua_block {
-- table是否包含指定元素方法
local function arr_include(tab, value)
for k,v in pairs(tab) do
if v == value then
return true
end
end
return false
end
local headers = ngx.req.get_headers();
local token = headers["token"];
-- 无token
if (token == nil) then
ngx.status = 403;
ngx.say(string.format("{\"success\":false,\"msg\":\"%s\"}", "token为空"));
return ngx.exit(403);
end
-- 黑名单
local guestIp = headers["X-Real-IP"] or headers["X-Forwarded-For"] or ngx.var.remote_addr;
local blacks = {"10.190.75.139"};
if (arr_include(blacks, guestIp)) then
ngx.status = 403;
ngx.say(string.format("{\"success\":false,\"msg\":\"%s\"}", "黑名单禁止访问"));
return ngx.exit(403);
end
-- 验签-读取请求体
ngx.req.read_body();
local reqBody = ngx.req.get_body_data();
-- 开始验签
local key = "A7409BB67B472E6CC7EF17C49784A6B8";
local digest = ngx.encode_base64(ngx.hmac_sha1(key, reqBody));
if (digest ~= token) then
ngx.status = 403;
ngx.say(string.format("{\"success\":false,\"msg\":\"%s\"}", "验签失败"));
return ngx.exit(403);
end
}
proxy_pass http://localhost/backend;
}
location /backend {
default_type "application/json";
content_by_lua_block {
ngx.say(string.format("{\"success\":true,\"msg\":\"%s\"}", "校验通过"));
return ngx.exit(200);
}
}
}
- nginx -s reload后测试