Я использую lua-resty-openidc
для реализации веб-интерфейса, который находится перед моей бэкэнд-системой.
Бэкэнд предоставляет REST API, защищенный заголовком Authorization
, содержащим JWT. Веб-интерфейс управляет сеансом и отправляет веб-пользователей поставщику удостоверений, если им необходимо войти в систему. Когда веб-пользователь имеет сеанс, веб-интерфейс должен найти JWT, добавить его в заголовок авторизации и прокси-запрос к бэкэнду. - довольно стандартный материал.
К сожалению, мой бэкэнд не проводит четкого различия guish между publi c и частными ресурсами. Например, у него могут быть ресурсы с URL-адресами:
/api/public/0
/api/public/1
/api/private/2
/api/private/3
Позволяет запрашивать /api/public/{0,1}
без заголовка авторизации, но /api/private/{2,3}
требует авторизации. Фронтенд должен как-то с этим справиться. ( Примечание: Упомянутые выше URL-адреса упрощены, реальные не соответствуют шаблону и не могут быть легко перечислены.)
Основная проблема в том, что интерфейс может не сообщайте из URI запроса, должен ли он вызывать логин . Он должен быть реактивным, передавать запрос на сервер и проверять код ответа. Код 401 должен заставить клиента войти в систему, но любой другой ответ должен быть возвращен как есть.
Из-за этого я не могу поместить свои auth logi c в блок access_by_lua
, так как они запускаются в фазе доступа до того, как запрос был отправлен в апстрим (бэкэнд).
Я попытался перевести мои логи c в фазу контента используя body_filter_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"
Можно ли выполнить openidc.authenticate()
в фазе содержимого из Nginx обработка запросов?
Есть ли лучший подход, который я должен использовать?