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 enabledelayedexpansion
set "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 nginx
echo "Install complate"
pause
然后执行命令即可一键安装新的Nginx服务:
更新nginx服务.bat
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 then
ngx.exit(400)
end
if token ~= "123" then
ngx.exit(401)
end
上述脚本获取get请求的token参数,判断值是否为123,不是123则鉴权不通过返回401。
下面我们为了实现与业务系统的权限一致,需要询问业务系统传入的token是否有效,这时就需要使用resty.http
:
local token = ngx.var.arg_token
if not token then
ngx.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 then
ngx.exit(402)
end
if res.body ~= "success" then
ngx.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;
附录
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/