Skip to content

Instantly share code, notes, and snippets.

@chaosong
Last active February 10, 2022 12:44
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save chaosong/7038017 to your computer and use it in GitHub Desktop.
Save chaosong/7038017 to your computer and use it in GitHub Desktop.
sso in nginx (by openresty)
local cjson = require('cjson')
local util = require('login_util')
if ngx.var.request_method ~= 'POST' then
ngx.log(ngx.WARN, 'request method is not post')
ngx.exit(400)
end
ngx.req.read_body()
local args = ngx.req.get_post_args()
if not args then
ngx.log(ngx.WARN, 'failed to get post args')
ngx.exit(400)
end
local token = args['token']
if not token then
ngx.log(ngx.WARN, 'token is nil')
ngx.exit(400)
end
local ref = args['ref']
if not ref then
ngx.log(ngx.WARN, 'ref is nil')
ngx.exit(400)
end
local resp = ngx.location.capture('/auth_verify', { args = { token = token } })
if resp.status ~= ngx.HTTP_OK then
ngx.log(ngx.WARN, 'verify token error: ', resp.status)
ngx.exit(500)
end
local js = cjson.decode(resp.body)
if not js['ret'] then
ngx.log(ngx.WARN, 'invalid token: ', token)
ngx.redirect(util.login_page)
end
local u = js['userId']
if not u then
ngx.log(ngx.WARN, 'invalid userId: ', u)
ngx.redirect(util.login_page)
end
util.set_auth(u)
local url = ngx.decode_base64(ref)
if util.is_safe_url(url) then
ngx.redirect(url)
else
ngx.redirect(util.default_page)
end
module(..., package.seeall)
login_page = '/login'
default_page = '/secret'
local salt = 'a_very_secret_key'
local expires = 24 * 3600
function encrypt(u, t)
local s = ngx.md5(u .. t .. salt)
return string.sub(s, 0, #s / 2)
end
function set_auth(u)
local nt = ngx.now() + expires
local t = tostring(nt)
local v = encrypt(u, t)
ngx.header['Set-Cookie'] = {
string.format('auth=%s|%s|%s; Expires=%s', u, t, v, ngx.cookie_time(nt))
}
end
function del_auth()
ngx.header['Set-Cookie'] = { 'auth=0|0|0; Expires=Thu, 01-Jan-1970 00:00:01 GMT' }
end
function check_auth(auth)
if not auth then
ngx.log(ngx.WARN, 'auth is empty')
return false
end
local r = {}
string.gsub(auth, '[^|]+', function(w) table.insert(r, w) end )
if not r or #r ~= 3 then
ngx.log(ngx.WARN, 'auth is malformed')
return false
end
local u, t, v = r[1], r[2], r[3]
local nt = tonumber(t)
if not nt or nt < ngx.now() then
ngx.log(ngx.WARN, 'auth is expired')
return false
end
if encrypt(u, t) ~= v then
ngx.log(ngx.WARN, 'auth is modified')
return false
end
return true
end
function is_safe_url(url)
if url and #url > 0 and url:sub(1, 1) == '/' then
return true
end
ngx.log(ngx.WARN, 'url error: ', url)
return false
end
access_by_lua "
local util = require('login_util')
local auth = ngx.var.cookie_auth
if not util.check_auth(auth) then
ngx.redirect(util.login_page .. '?ref=' .. ngx.encode_base64(ngx.var.request_uri))
end
ngx.log(ngx.WARN, auth, ' is logging in')
";
location /secret {
include need_login.conf;
default_type text/plain;
content_by_lua "
ngx.say('我是默认页啦~ 登录后可以正常跳转回来到此。')
local args = ngx.req.get_uri_args()
for key, val in pairs(args) do
if type(val) == 'table' then
ngx.say(key, ': ', table.concat(val, ', '))
else
ngx.say(key, ': ', val)
end
end
";
}
location /auth_callback {
rewrite_by_lua_file 'conf/auth_callback.lua';
}
resolver 114.114.114.114;
location /auth_verify {
internal;
proxy_pass http://qsso.corp.qqqqq.com/api/verifytoken.php?token=$arg_token;
}
location /login {
default_type text/html;
set_by_lua $t 'return ngx.now()';
echo "
<html>
<head>
<script src='https://qsso.corp.qqqqq.com/lib/qsso-auth.js?t=$t'></script>
</head>
<body>
<button id='qsso-login'>QSSO Login</button>
<script type='text/javascript'>
QSSO.attach('qsso-login','/auth_callback', { 'ref': '$arg_ref' });
</script>
</body>
</html>
";
}
location /logout {
rewrite_by_lua "
local util = require('login_util')
util.del_auth()
ngx.redirect(util.login_page)
";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment