最近在公司作一个简单的portal,原本很简单的,只用ngx_lua就能够实现全部的业务逻辑,不须要upstream上游服务。但被要求接入公司内部的用户校验系统,说白了就是一个登陆过程,只容许公司内部的用户能够登陆访问。php
公司内部有一整套组件,只要在业务代码里嵌入改组件,就能自动检测用户是否已经登陆、或session是否过时,是则跳转到登陆界面,用户输入密码验证后,从新跳转会原始访问的页面。java
但公司提供的组件都是基于经常使用的业务语言的,如php、java,我也不想再加上这些玩意,因而考虑用ngx_lua实现这样一套登陆逻辑。下面是一个测试配置,基本总结了nginx中实现登陆的方法。nginx
lua_shared_dict stats 10m; init_by_lua ' local stats = ngx.shared.stats stats:set("flag",1) '; server { listen 80 so_keepalive=on; set $flag 0; rewrite_by_lua ' local stdo = string.match(ngx.var.uri, "(%a+%.do)") if stdo == nil then local res = ngx.location.capture("/isLoginExpired.do") ngx.var.flag = res.body end '; location /isLoginExpired.do { content_by_lua ' local stats = ngx.shared.stats local flag = stats:get("flag") ngx.print(flag) '; } location / { content_by_lua ' if ngx.var.flag == "1" then local query = "backuri="..ngx.var.request_uri query = string.gsub(query,"&","%%26") return ngx.redirect("/redirect?"..query, 302) else local new_uri = "/fcgi"..ngx.var.request_uri ngx.exec("/fcgi") end '; } location /redirect { content_by_lua ' local stats = ngx.shared.stats -- do login or update cookies, and then flag=0 stats:set("flag",0) local backuri = ngx.var.arg_backuri return ngx.redirect(backuri, 302) '; } location /fcgi { content_by_lua ' ngx.say(ngx.var.request_uri) ngx.say("come into fcgi") ngx.say(ngx.var.flag) ngx.say(ngx.var.right) '; } }
这里用共享内存 stats:flag模拟是否登陆的标志位,初始为1,表示未登陆。cookie
对于全部请求,首先用一段rewrite_by_lua代码来判断是否登陆,这里主要就是查看stats:flag的值,其中能够利用ngx_lua提供的强大的子请求功能。这里要注意的是,所用子请求的uri必定要排除在要判断登陆态请求以外(即该/isLoginExpired.do请求不能再去判断登陆态,不然会形成死循环)。session
以后全部请求进入 location / {...},这里主要利用前面判断的结果(ngx.var.flag的值,不要和那个stats:flag混淆了,名字没起好),没有登陆,则利用ngx.redirect()作302跳转,跳转到登陆界面,用户能够输入密码,这里简单的模拟了一下,直接把stats:flag置0,而且添加query语句,带上backuri字段。测试
通常登陆应用中,都会读取backuri字段,登陆认证后,从新302到该backuri。例子中的location /redirect {...} 就是模拟了这样一个登陆应用。lua
请求从新来以后,进入location / {...}, 判断已登陆,则经过ngx.exec()直接内部跳转到具体的业务location。spa
一开始的时候仍是以为比较绕的,理清楚以后仍是比较简洁的,这里面用到ngx_lua的几个强大的功能,也是一次很好的实践code
ngx.location.capture() 子请求server
ngx.redirect() 等同于nginx原生的rewrite .. .. redirect (302跳转)
ngx.exec() 等同于nginx原生的rewrite .. .. break (内部跳转)
运行结果以下
不当之处,欢迎指正