我正在使用lua-resty-openidc实现一个位于后端系统前面的web。
后端提供一个REST,由包含JWT的Authorization头保护。前端管理会话,如果用户需要登录,则将其发送给身份提供者。当web用户有会话时,前端必须查找JWT,将其添加到授权头,并将请求代理到后端--非常标准的内容。
不幸的是,我的后端并没有明确区分公共资源和私人资源。例如,它可能有带有URL的资源:
/api/public/0/api/public/1/api/private/2/api/private/3它允许在没有授权头的情况下请求/api/public/{0,1},但是/api/private/{2,3}需要授权。前面的人必须以某种方式处理这件事。(注意:上面的URL是简化的,真实的URL不遵循模式,很难被枚举。)
核心问题是前端无法从请求URI中判断是否应该触发登录。它必须是反应性的,将请求代理到后端并检查响应代码。401代码应强制客户端登录,但任何其他响应都应按原样返回。
因此,我不能将我的auth逻辑放在access_by_lua块中,因为它们在访问阶段中运行,然后请求被发送到上游(后端)。
我尝试使用一个块将我的逻辑移到内容阶段:
location /api {
set $session_storage shm;
proxy_set_header X-Forwarded-Host $http_host;
proxy_pass https://backend;
body_filter_by_lua_block {
if ngx.status == ngx.HTTP_UNAUTHORIZED then
ngx.log(ngx.INFO, 'Upstream returned a 401! Triggering auth flow')
local opts = {
discovery = 'https://login-server/.well-known/openid-configuration',
scope = 'openid',
}
local res, err = openidc.authenticate(opts)
if err or not res then
ngx.status = ngx.HTTP_UNAUTHORIZED
ngx.header.content_type = 'text/html';
ngx.log(ngx.ERR, err)
ngx.say("Forbidden")
ngx.exit(ngx.HTTP_UNAUTHORIZED)
end
end
}
}…但如果出现错误(如下所示),则会失败。在请求处理生命周期中,设置头和cookie似乎为时已晚:
*194 [lua] body_filter_by_lua:5: Upstream returned a 401! Triggering auth flow while sending to client, client: 10.255.1.2, server: , request: "GET /api/private/2 HTTP/1.1", upstream: "https://backend/api/private/2", host: "frontend.example.org"
*194 [lua] openidc.lua:1363: authenticate(): Error starting session: Attempt to set session cookie after sending out response headers. while sending to client, client: 10.255.1.2, server: , request: "GET /api/private/2 HTTP/1.1", upstream: "https://backend/api/private/2", host: "frontend.example.org"
*194 attempt to set ngx.status after sending out response headers while sending to client, client: 10.255.1.2, server: , request: "GET /api/private/2 HTTP/1.1", upstream: "https://backend/api/private/2", host: "frontend.example.org"是否可以在Nginx请求处理的openidc.authenticate()内容阶段执行?
有什么更好的方法吗?
发布于 2020-11-30 14:47:57
最后,我调整了后端使用的URL模式,这样可以预先区分私有URL和公共URL。然后,前端逻辑变得简单起来:
对公共资源的backend
我不知道我最初的问题(先代理,然后根据响应代码做出决定)在OpenResty中是否可行。但最终,我认为新的方法还是比较干净的。
https://stackoverflow.com/questions/60657661
复制相似问题