Nginx服务
对非同源地址的nginx配置要求
http同端口访问http跳转https(497错误)
关于Nginx 的 location 匹配规则总结
Nginx+LUA+Redis实现token访问鉴权
Nginx实现后端Server域名动态解析
Nginx反向代理跨域问题
浏览器报错ERR_CONTENT_LENGTH_MISMATCH
Nginx常见HTTP Code错误排查
使用acme.sh部署证书至Nginx
Nginx在普通用户下使用特权端口 (443端口)
Nginx配置自定义状态页
try_files和alias的组合使用
Nginx中301重定向导致端口丢失
本文档使用 MrDoc 发布
-
+
home page
Nginx+LUA+Redis实现token访问鉴权
Nginx采用已集成lua环境的Openresty程序 ### 1、环境需求 Openresty程序 已搭建的redis程序 ### 2、在Nginx中部分配置 需要在`nginx.conf`中引入如下配置文件 ```bash [root@0005 ~]# cat /data/openresty/nginx/conf/lua.conf lua_package_path "/data/openresty/lualib/?.lua;;/data/openresty/nginx/conf/openResty/?.lua;;"; #lua 模块 lua_package_cpath "/data/openresty/lualib/?.so;"; server { listen *:88; server_name localhost; location /lua_access_1 { default_type "text/html"; access_by_lua_file /data/openresty/nginx/conf/redis.lua; echo "access"; #此处为可访问路径,自定义 } location /getTime { default_type text/html; content_by_lua ' ngx.say(ngx.time() * 1000); '; } } ``` ### 3、Lua脚本的全部配置 该脚本的主要流程如下: 1)验证请求的时间戳是否合法,如果合法,继续执行,否则返回403 2)验证请求的token是否存在,如果存在,继续执行,否则返回403 3)验证请求的token是否正确,如果正确,继续执行,否则返回403 4)验证请求的token是否存在于redis中,如果不存在,允许访问,并将该token写入redis,否则返回403 ```lua [root@0005 ~]# cat /data/openresty/nginx/conf/redis.lua -- 允许访问的最大时间范围(单位:毫秒,正确时间的±范围值) local allowMaxTime = 100000 -- MD5校验指定的盐值 local salt = "salt" -- redis连接信息 local ip = "192.168.27.239" local port = 6800 local passwd = "admin" local function close_redis(red) if not red then return end local ok,err = red:close(); if not ok then ngx.say("close redis error : ",err); end end local json = require "cjson"; -- 获取请求路径,不包括参数。例如:/group/456.png local uri = ngx.var.uri; -- 获取请求参数 local args = ngx.req.get_uri_args(); -- 获取请求参数中时间戳信息,传入的是毫秒 local ts = args["ts"]; -- 获取请求参数中 token 信息 local token = args["token"]; -- 更新系统缓存时间戳 ngx.update_time(); -- 获取当前服务器系统时间,ngx.time() 获取的是秒 local getTime = ngx.time() * 1000; -- 计算时间差 local diffTime = getTime - tonumber(ts); -- md5 加盐加密 -- ngx.say(ts," ",token," ",diffTime," ",tonumber(-allowMaxTime)) if ( tonumber(allowMaxTime) < tonumber(diffTime) or tonumber(diffTime) < tonumber(-allowMaxTime) ) then -- ngx.status = 403 ngx.log(ngx.WARN,"The invalid timestamp: currentTime: [",getTime,"] interviewTime: [",ts,"] TimeDiff: ",diffTime) ngx.exit(ngx.HTTP_FORBIDDEN) end if token == nil or token == "" then -- ngx.status = 403 ngx.log(ngx.WARN,"Invalid token: The access token is empty") ngx.exit(ngx.HTTP_FORBIDDEN) else local token2 = ngx.md5(tostring(uri) .. salt .. tostring(ts)); -- ngx.say(tostring(uri) .. salt .. tostring(ts)," ",token2," ",token) if token == token2 then local redis = require "resty.redis"; local red = redis:new(); -- 允许的最大毫秒数 red:set_timeout(1000) local ok,err = red:connect(ip,port) if not ok then -- ngx.status = 500 ngx.log(ngx.ERR,"failed to connect to redis: ",err) ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) end local res, err = red:auth(passwd) if not res then -- ngx.status = 500 ngx.log(ngx.ERR,"failed to verify redis with password: ",err) ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) end local resp, err = red:get(token) resp = tostring(resp) if tostring(resp) == 'userdata: NULL' then ok, err = red:set(token, ts) if not ok then -- ngx.status = 500 ngx.log(ngx.ERR,"failed to insert token in redis: ", err) ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) -- return end return else -- ngx.status = 403 ngx.log(ngx.WARN,"invalid token: already exists in redis: token: [",token,"] timestamp: [",resp,"]") ngx.exit(ngx.HTTP_FORBIDDEN) end else -- ngx.status = 403 ngx.log(ngx.WARN,"invalid token: token verification failed: correct value: [",token2,"] user value: [",token,"]") ngx.exit(ngx.HTTP_FORBIDDEN) end end ``` 配置完毕后需要重启openresty后生效 ### 4、其他说明 #### 4.1、新增Lua的Redis模块 连接redis集群需要用到 lua-resty-redis-cluster模块 github地址: https://github.com/cuiweixie/lua-resty-redis-cluster 或可直接下载附件[【附件】lua-resty-redis-cluster-master.zip](/media/attachment/2021/11/lua-resty-redis-cluster-master.zip) 下载完成之后,只需要用到包中的2个文件rediscluster.lua和redis_slot.c 复制包中的 `redis_slot.c` 到`openresty/lualib`下 复制包中的`rediscluster.lua`到`openresty/lualib/resty`下 `C`后缀文件无法在Nginx配置文件中引入,需要编译成`.so`文件 编译命令如下 ```bash yum -y install gcc gcc-c++ kernel-devel # centos自带lua需要执行此命令再编译,自己安装过lua不需要 yum install lua-devel #编译命令 gcc redis_slot.c -fPIC -shared -o libredis_slot.so #查看结果如下 [root@0005 ~]# ll /data/openresty/lualib/libredis_slot.so -rwxr-xr-x 1 root root 8072 Nov 12 18:01 /data/openresty/lualib/libredis_slot.so ``` #### 4.2、Nginx中开启告警日志 ``` error_log logs/error.log warn; ``` ### 5、测试结果 说明: 1、当时间戳和token错误后返回拒绝 2、当全部正确后允许访问 3、使用相同时间戳和token再次访问时再次拒绝 ![](/media/202111/lua验证token_1636947527.gif)
Nathan
Nov. 15, 2021, 11:43 a.m.
转发文档
Collection documents
Last
Next
手机扫码
Copy link
手机扫一扫转发分享
Copy link
Markdown文件
PDF文件
Docx文件
share
link
type
password
Update password