local json = require("cjson") local http = require("resty.http") local uri = ngx.var.uri local uri_args = ngx.req.get_uri_args() local scheme = ngx.var.scheme local corp_id = ngx.var.corp_id local agent_id = ngx.var.agent_id local secret = ngx.var.secret local callback_scheme = ngx.var.callback_scheme or scheme local callback_host = ngx.var.callback_host local callback_uri = ngx.var.callback_uri local use_secure_cookie = ngx.var.use_secure_cookie == "true" or false local callback_url = callback_scheme .. "://" .. callback_host .. callback_uri local redirect_url = callback_scheme .. "://" .. callback_host .. ngx.var.request_uri local logout_uri = ngx.var.logout_uri or "/logout" local token_expires = ngx.var.token_expires or "7200" token_expires = tonumber(token_expires) local function request_access_token(code) local request = http.new() request:set_timeout(7000) local res, err = request:request_uri("https://qyapi.weixin.qq.com/cgi-bin/gettoken", { method = "GET", query = { corpid = corp_id, corpsecret = secret, }, ssl_verify = true, }) if not res then return nil, (err or "access token request failed: " .. (err or "unknown reason")) end if res.status ~= 200 then return nil, "received " .. res.status .. " from https://qyapi.weixin.qq.com/cgi-bin/gettoken: " .. res.body end local data = json.decode(res.body) if data["errcode"] ~= 0 then return nil, data["errmsg"] else return data["access_token"] end end local function request_user(access_token, code) local request = http.new() request:set_timeout(7000) local res, err = request:request_uri("https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo", { method = "GET", query = { access_token = access_token, code = code, }, ssl_verify = true, }) if not res then return nil, "get profile request failed: " .. (err or "unknown reason") end if res.status ~= 200 then return nil, "received " .. res.status .. " from https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo" end local userinfo = json.decode(res.body) if userinfo["errcode"] == 0 then if userinfo["UserId"] then res, err = request:request_uri("https://qyapi.weixin.qq.com/cgi-bin/user/get", { method = "GET", query = { access_token = access_token, userid = userinfo["UserId"], }, ssl_verify = true, }) if not res then return nil, "get user request failed: " .. (err or "unknown reason") end if res.status ~= 200 then return nil, "received " .. res.status .. " from https://qyapi.weixin.qq.com/cgi-bin/user/get" end local user = json.decode(res.body) if user["errcode"] == 0 then return user else return nil, user["errmsg"] end else return nil, "UserId not exists" end else return nil, userinfo["errmsg"] end end local function is_authorized() local headers = ngx.req.get_headers() local expires = tonumber(ngx.var.cookie_OauthExpires) or 0 local user_id = ngx.unescape_uri(ngx.var.cookie_OauthUserID or "") local token = ngx.var.cookie_OauthAccessToken or "" if expires == 0 and headers["OauthExpires"] then expires = tonumber(headers["OauthExpires"]) end if user_id:len() == 0 and headers["OauthUserID"] then user_id = headers["OauthUserID"] end if token:len() == 0 and headers["OauthAccessToken"] then token = headers["OauthAccessToken"] end local expect_token = callback_host .. user_id .. expires if token == expect_token and expires then if expires > ngx.time() then return true else return false end else return false end end local function redirect_to_auth() return ngx.redirect("https://open.work.weixin.qq.com/wwopen/sso/qrConnect?" .. ngx.encode_args({ appid = corp_id, agentid = agent_id, redirect_uri = callback_url, state = redirect_url })) end local function authorize() if uri ~= callback_uri then return redirect_to_auth() end local code = uri_args["code"] if not code then ngx.log(ngx.ERR, "not received code from https://open.work.weixin.qq.com/wwopen/sso/qrConnect") return ngx.exit(ngx.HTTP_FORBIDDEN) end local access_token, request_access_token_err = request_access_token(code) if not access_token then ngx.log(ngx.ERR, "got error during access token request: " .. request_access_token_err) return ngx.exit(ngx.HTTP_FORBIDDEN) end local user, request_user_err = request_user(access_token, code) if not user then ngx.log(ngx.ERR, "got error during profile request: " .. request_user_err) return ngx.exit(ngx.HTTP_FORBIDDEN) end ngx.log(ngx.ERR, "user id: " .. user["userid"]) local expires = ngx.time() + token_expires local cookie_tail = "; version=1; path=/; Max-Age=" .. expires if use_secure_cookie then cookie_tail = cookie_tail .. "; secure" end local user_id = user["userid"] local user_token = callback_host .. user_id .. expires ngx.header["Set-Cookie"] = { "OauthUserID=" .. ngx.escape_uri(user_id) .. cookie_tail, "OauthAccessToken=" .. ngx.escape_uri(user_token) .. cookie_tail, "OauthExpires=" .. expires .. cookie_tail, } return ngx.redirect(uri_args["state"]) end local function handle_logout() if uri == logout_uri then ngx.header["Set-Cookie"] = "OauthAccessToken==deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT" --return ngx.redirect("/") end end handle_logout() if (not is_authorized()) then authorize() end |