介绍
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) doif v == value thenreturn trueendendreturn falseendlocal headers = ngx.req.get_headers();local token = headers["token"];-- 无tokenif (token == nil) thenngx.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)) thenngx.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) thenngx.say(string.format("{\"success\":true,\"msg\":\"%s\"}", "校验通过"));elsengx.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) doif v == value thenreturn trueendendreturn falseendlocal headers = ngx.req.get_headers();local token = headers["token"];-- 无tokenif (token == nil) thenngx.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)) thenngx.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) thenngx.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后测试