来源:https://openresty-reference.readthedocs.io/en/latest/Directives/#access_by_lua
openresty 有很多适配 nginx 的段,其中 access_by_lua
/access_by_lua_block
可以用于权限认证。
在 nginx 的 server 段中增加如下的 location
,其中的 lua
代码用来进行验证。
Note that when calling
ngx.exit(ngx.OK)
within a access_by_lua handler, the nginx request processing control flow will still continue to the content handler. To terminate the current request from within a access_by_lua handler, calling ngx.exit with status >= 200 (ngx.HTTP_OK) and status < 300 (ngx.HTTP_SPECIAL_RESPONSE) for successful quits and ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) (or its friends) for failures.
意思是 ngx.exit
的值在 200 <= status < 300
的时候,控制流会继续向下走,而当 ngx.exit
是 ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
或者其类似的错误码时,则会中止控制流。
文档中的代码示例
location / {
access_by_lua '
local res = ngx.location.capture("/auth")
if res.status == ngx.HTTP_OK then
return
end
if res.status == ngx.HTTP_FORBIDDEN then
ngx.exit(res.status)
end
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
';
# proxy_pass/fastcgi_pass/postgres_pass/...
}
测试代码示例
- 先解决一下 lua 的
redis
无法解析本地域名的问题,使用的库是lua-local-resolver
,代码仓库 https://github.com/ysugimoto/lua-local-resolver 需要先在 server 同级别添加一个init_by_lua_file lualibs/init.lua;
,而init.lua
中的代码是
package.path = package.path .. ";/usr/local/openresty/nginx/lualibs/?.lua"
- 连接
redis
- 从 http header 里面获取
Token
- 从
redis
中获取 token 对应的值 - 判断值是否为空
这其中的任何一个步骤失败了,都要返回一个 ngx.exit(ngx.HTTP_FORBIDDEN)
,中止后面的操作。
如果都成功了,那么就继续向下走,直接走到 proxy_pass
配置代码如下
location / {
access_by_lua_block {
local resolver = require "local-resolver"
resolver = resolver.new("/etc/hosts")
local redis = require "resty.redis"
local red = redis:new()
local ok, err = red:connect(resolver:resolve("openresty_kvrocks"), 6666)
if not ok then
--ngx.say("HTTP_UNAUTHORIZED: ", "x")
--ngx.say("failed to connect cache: ", err)
ngx.log(ngx.ERR, err)
ngx.exit(ngx.HTTP_FORBIDDEN)
return
end
local token = ngx.req.get_headers()['Token']
if token == nil then
token = "null"
end
local key = "resty:auth:access:token:" .. token
local res, err = red:get(key)
if not res then
ngx.log(ngx.ERR, "get redis key failed: " .. key)
ngx.exit(ngx.HTTP_FORBIDDEN)
return
end
if res == ngx.null then
ngx.log(ngx.ERR, "get redis key empty: " .. key)
ngx.exit(ngx.HTTP_FORBIDDEN)
return
end
--ngx.say(ngx.req.get_headers()['Token'])
}
proxy_pass http://simple_server;
proxy_connect_timeout 18000;
proxy_send_timeout 18000;
proxy_read_timeout 18000;
client_max_body_size 10240m;
}