小小明-代码实体

小小明-代码实体

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.exenginx-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目录中。

OpenResty(nginx+lua+resty-http)实现访问鉴权-LMLPHP

这样我们就满足在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(nginx+lua+resty-http)实现访问鉴权-LMLPHP

openresty中文站:http://openresty.org/cn/

12-05 06:34