最近在公司作一個簡單的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 (內部跳轉)
運行結果以下
不當之處,歡迎指正