OpenResty(nginx+lua+resty-http)实现访问鉴权
最近用BI框架解决了一些报表需求并生成了公开链接,现在CMS开发人员打算将其嵌入到业务系统中,结果发现公开链接一旦泄露任何人都可以访问,需要实现BI系统报表与业务系统同步的权限控制。但是目前使用的BI框架并不支持这样的功能,如果自己修改BI系统去实现这样的功能开发成本太高。
基于这样的背景下,我想到了使用Nginx网关来实现目标页面的鉴权。结果发现了OpenResty,下面我将实操过程分享给大家。这次使用了PowerBI和其他BI系统,所测试的服务器为Windows Server系统。其他系统的具体操作细节会有所区别,下面我只以Windows系统为例进行演示。
OpenResty 简介与安装
OpenResty 是一个基于 Nginx 和 LuaJIT 的动态 web 平台。它通过在 Nginx 中集成 LuaJIT,允许在 Nginx 服务器上运行 Lua 脚本,增加了 Nginx 的灵活性和可扩展性。
官网下载页:http://openresty.org/en/download.html
首先下载openresty-1.21.4.3-win64.zip 并解压
原版Nginx带有nginx-service.exe
可以很方便的将Nginx注册为系统服务。
下面我复制原版Nginx中的nginx-service.exe
和nginx-service.xml
文件 到 新解压的 E:\soft\openresty-1.21.4.3-win64
目录中。
若以前的Nginx已经注册服务可以使用以下命令先取消注册:
nginx-service.exe uninstall nginx
然后修改nginx-service.xml
文件为如下内容:
<service><!-- 服务名 --><id>nginx</id><!-- 显示名称 --><name>Nginx Service</name><!-- 描述 --><description>High Performance Nginx Service</description><logpath>E:\soft\openresty-1.21.4.3-win64\logs</logpath><log mode="roll-by-size"><sizeThreshold>10240</sizeThreshold><keepFiles>8</keepFiles></log><executable>E:\soft\openresty-1.21.4.3-win64\nginx.exe</executable><startarguments>-p E:\soft\openresty-1.21.4.3-win64</startarguments><stopexecutable>E:\soft\openresty-1.21.4.3-win64\nginx.exe</stopexecutable><stoparguments>-p E:\soft\openresty-1.21.4.3-win64 -s stop</stoparguments>
</service>
然后执行即可将新安装的OpenResty 的Nginx注册为服务:
nginx-service.exe install nginx
可以将上述过程用bat脚本自动化,首先创建文件nginx-service-template.xml
,内容如下:
<service><id>nginx</id><name>Nginx Service</name><description>High Performance Nginx Service</description><logpath>{{dir}}\logs</logpath><log mode="roll-by-size"><sizeThreshold>10240</sizeThreshold><keepFiles>8</keepFiles></log><executable>{{dir}}\nginx.exe</executable><startarguments>-p {{dir}}</startarguments><stopexecutable>{{dir}}\nginx.exe</stopexecutable><stoparguments>-p {{dir}} -s stop</stoparguments>
</service>
然后创建bat脚本安装nginx服务.bat
:
@echo off
setlocal enabledelayedexpansionset "path=%~dp0"
set "path=%path:~0,-1%"
>"nginx-service.xml" (for /f "delims=" %%i in ('type "nginx-service-template.xml"') do (set "line=%%i"set "line=!line:{{dir}}=%path%!"echo(!line!)
)
nginx-service.exe uninstall nginx
nginx-service.exe install nginxecho "Install complate"
pause
然后执行命令即可一键安装新的Nginx服务:
更新nginx服务.bat
注意:以上脚本都在
openresty-1.21.4.3-win64
的安装目录下,一键生成配置并安装服务。
resty.http的安装
我们的鉴权脚本需要http请求目标服务,但是resty.http
并未集成到openresty中,所以需要我们自行下载。
下载地址为:https://github.com/ledgetech/lua-resty-http
将lib/resty目录下的三个lua脚本复制到openresty-1.21.4.3-win64\lualib\resty
目录中。
这样我们就满足在lua脚本中发起http请求的基本条件。
lua鉴权脚本编写
首先我们实现一个基本的鉴权脚本:
local token = ngx.var.arg_token
if not token thenngx.exit(400)
end
if token ~= "123" thenngx.exit(401)
end
上述脚本获取get请求的token参数,判断值是否为123,不是123则鉴权不通过返回401。
下面我们为了实现与业务系统的权限一致,需要询问业务系统传入的token是否有效,这时就需要使用resty.http
:
local token = ngx.var.arg_token
if not token thenngx.exit(400)
end
local http = require "resty.http"
local httpc = http.new()
local url = "https://业务系统提供的接口地址?token="..token
local res, err = httpc:request_uri(url, {method = "GET",headers = {["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.289 Safari/537.36",},ssl_verify = false
})
if not res thenngx.exit(402)
end
if res.body ~= "success" thenngx.exit(403)
end
以上脚本根据业务系统是否返回success,决定鉴权是否通过。
请求中使用ssl_verify = false
是因为 Nginx 服务器无法验证服务器的 SSL证书,因为它没有正确配置必要的根证书,相对给Nginx配置根证书,直接取消验证更简单一些。
resty.http
更多用法:https://github.com/ledgetech/lua-resty-http#request
Nginx配置鉴权脚本
下面我们配置Nginx的核心脚本:
http {map $http_upgrade $connection_upgrade { default upgrade;'' close;}...server {listen 80;server_name localhost;location ^~ /xxx/websocket {proxy_pass http://localhost:9999;proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection $connection_upgrade;}location /xxx/ {rewrite_by_lua_file lua/auth.lua;proxy_pass http://localhost:9999;proxy_hide_header X-Frame-Options;proxy_hide_header Content-Security-Policy;proxy_hide_header X-Xss-Protection;add_header Access-Control-Allow-Origin *;}}resolver 8.8.8.8;
}
上面最核心的配置是rewrite_by_lua_file lua/auth.lua;
注意:resolver是必须配置的,用于配置DNS服务器,否则
auth.lua
脚本的HTTP请求无法正确获取响应。rewrite_by_lua_file 指定了前面编写的鉴权脚本
lua/auth.lua
,相对openresty所在的根目录下。
附录
lua读取请求参数的其他用法
--获取请求header
local reqHeaders = ngx.req.get_headers();
--读取cookie中的pcip值
local pcip = ngx.var.cookie_pcip;
--获取请求URI
local requestUri = ngx.var.request_uri;
--获取请求域名
local requestHost = ngx.var.host;
----获取请求方法类型GET POST
local reqType= ngx.var.request_method;
openresty的基本框架
openresty中文站:http://openresty.org/cn/