access_check.lua 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. local resty_cookie = require("resty.cookie") -- https://github.com/cloudflare/lua-resty-cookie
  2. local util = require("util")
  3. local json = require("json")
  4. local agent_pub = require("agent_pub")
  5. local config = require("config")
  6. local login_url = "/wolf/rbac/login.html"
  7. local no_permission = "/wolf/rbac/no_permission"
  8. local no_permission_html = "/wolf/rbac/no_permission.html"
  9. local access_check_url = "/wolf/rbac/access_check"
  10. function get_token()
  11. local cookie, err = resty_cookie:new()
  12. if not cookie then
  13. ngx.log(ngx.ERR, "resty_cookie:new() failed!", err)
  14. return nil
  15. end
  16. local token_key = "x-rbac-token"
  17. local token, err = cookie:get(token_key)
  18. return token
  19. end
  20. local function get_host_port()
  21. local host = ngx.var.host
  22. local port = ""
  23. if ngx.var.server_port and ngx.var.server_port ~= 80 then
  24. port = ":" .. tostring(ngx.var.server_port)
  25. end
  26. local host_port = (ngx.var.scheme or "http") .. "://" .. host .. port
  27. return host_port
  28. end
  29. local function url_args_as_args(ext_args)
  30. local args = ngx.req.get_uri_args()
  31. local host_port = get_host_port()
  32. local full_url = host_port .. ngx.var.uri
  33. args["return_to"] = full_url
  34. if ext_args and type(ext_args) == 'table' then
  35. for k, v in pairs(ext_args) do
  36. args[k] = v
  37. end
  38. end
  39. return args
  40. end
  41. local function check_url_permission(appID, action, resName, clientIP)
  42. local retry_max = 3
  43. local reason = nil;
  44. local userInfo = nil
  45. local res = nil
  46. for i = 1, retry_max do
  47. local args = { appID = appID, resName = resName, action = action, agentName=config.agentName, clientIP=clientIP}
  48. local url = access_check_url .. "?" .. ngx.encode_args(args)
  49. res = ngx.location.capture(url)
  50. if res then
  51. ngx.log(ngx.INFO, "check permission request:", url, ", status:", res.status, ",body:", tostring(res.body))
  52. if res.status < 500 then
  53. break
  54. else
  55. ngx.log(ngx.ERR, string.format("request [curl -v %s] failed! status:%d", url, res.status))
  56. end
  57. else
  58. reason = 'check permission failed, check request failed!'
  59. ngx.log(ngx.ERR, "fail request: ", url)
  60. end
  61. end
  62. if not res then
  63. return false, 500, reason
  64. end
  65. if res.status ~= 200 then
  66. local strBody = util.trim(res.body or "")
  67. local body, err = json.loads(strBody)
  68. if err then
  69. userInfo = res.body
  70. reason = 'check permission failed! parse response json failed!'
  71. else
  72. userInfo = body.data.userInfo
  73. reason = body.reason
  74. end
  75. return false, res.status, reason, userInfo, res.headers
  76. else
  77. local body, err = json.loads(res.body)
  78. if err then
  79. userInfo = res.body
  80. reason = 'check permission failed! parse response json failed!'
  81. ngx.log(ngx.ERR, "json.loads(", res.body, ") failed! err:", err)
  82. else
  83. userInfo = body.data.userInfo
  84. reason = body.reason
  85. end
  86. return true, res.status, reason, userInfo, res.headers
  87. end
  88. end
  89. local function url_redirect(url, args)
  90. local appID = ngx.var.appID or "appIDUnset"
  91. args.appid = appID
  92. args = ngx.encode_args(args)
  93. util.redirect(url, args)
  94. end
  95. local function access_check()
  96. local url = ngx.var.uri
  97. local action = ngx.req.get_method()
  98. if util.url_in_ignore_list(url) then
  99. ngx.log(ngx.INFO, "check permission, ignore current request!")
  100. return
  101. end
  102. local appID = ngx.var.appID or "appIDUnset"
  103. local clientIP = util.clientIP()
  104. local permItem = "{appID: " .. appID .. ", action: " .. action .. ", url: " .. url .. ", clientIP: " .. clientIP .. "}"
  105. ngx.log(ngx.INFO, "Cookie: ", ngx.var.http_cookie, ", permItem=", permItem)
  106. local token = get_token()
  107. if token == nil then
  108. ngx.log(ngx.WARN, "no permission to access ", permItem, ", need login!")
  109. url_redirect(login_url, url_args_as_args())
  110. elseif token == "logouted" then
  111. ngx.log(ngx.WARN, "logouted, no permission to access [", permItem, "], need login!")
  112. url_redirect(login_url, url_args_as_args())
  113. end
  114. ngx.ctx.token = token
  115. local ok, status, reason, userInfo, headers = check_url_permission(appID, action, url, clientIP)
  116. ngx.log(ngx.INFO, " check_url_permission(", permItem, ",token=", tostring(token), ")=",
  117. ok, ", status:", tostring(status), ", userInfo:", tostring(json.dumps(userInfo)))
  118. local userID = -1
  119. local username = nil
  120. local nickname = nil
  121. if type(userInfo) == 'table' then
  122. ngx.req.set_header("X-UserId", userInfo.id)
  123. ngx.req.set_header("X-Username", userInfo.username)
  124. ngx.req.set_header("X-nickname", ngx.escape_uri(userInfo.nickname) or userInfo.username)
  125. -- local args = ngx.req.get_uri_args()
  126. ngx.ctx.userInfo = userInfo
  127. userID = userInfo.id
  128. username = userInfo.username
  129. nickname = userInfo.nickname
  130. end
  131. if headers and headers["Set-Cookie"] then
  132. local cookie_value = headers["Set-Cookie"]
  133. ngx.header['Set-Cookie'] = cookie_value
  134. ngx.log(ngx.INFO, "******* Re Set-Cookie:", cookie_value, " *******")
  135. end
  136. if ok then
  137. ---
  138. else
  139. -- no permission.
  140. if status == ngx.HTTP_UNAUTHORIZED or status == ngx.HTTP_FORBIDDEN then
  141. if reason == "ERR_TOKEN_INVALID" then
  142. url_redirect(login_url, url_args_as_args())
  143. else
  144. local redirect_url = no_permission
  145. if url == '/' then
  146. redirect_url = no_permission_html
  147. end
  148. url_redirect(redirect_url, { username = username, reason=reason })
  149. end
  150. elseif status == ngx.HTTP_BAD_REQUEST then
  151. ngx.status = ngx.HTTP_INTERNAL_SERVER_ERROR
  152. ngx.header["Content-Type"] = "text/plain"
  153. ngx.send_headers()
  154. ngx.flush(true)
  155. ngx.say("rbac check permission failed! status:" .. tostring(status))
  156. ngx.flush(true)
  157. else
  158. ngx.status = status
  159. ngx.header["Content-Type"] = "text/plain"
  160. ngx.send_headers()
  161. ngx.flush(true)
  162. ngx.say("rbac check permission failed! status:" .. tostring(status))
  163. ngx.flush(true)
  164. end
  165. end
  166. end
  167. access_check()