Запуск аутентификации openidc на основе кода состояния восходящего потока

Я использую lua-resty-openidc реализовать веб-интерфейс, который находится перед моей серверной системой.

Бэкэнд предоставляет REST API, защищенный Authorizationзаголовок, содержащий JWT. Интерфейс управляет сеансом и отправляет веб-пользователей поставщику удостоверений, если им нужно войти в систему. Когда веб-пользователь имеет сеанс, интерфейс должен искать JWT, добавлять его в заголовок авторизации и передавать запрос на серверную часть. - довольно стандартные штучки.

К сожалению, мой бэкэнд не делает четкого различия между общедоступными и частными ресурсами. Например, у него могут быть ресурсы с URL-адресами:

  • /api/public/0
  • /api/public/1
  • /api/private/2
  • /api/private/3

Это позволяет /api/public/{0,1} быть запрошенным без заголовка авторизации, но /api/private/{2,3}требуется авторизация. Веб-интерфейс должен как-то с этим справляться. (Примечание: приведенные выше URL-адреса упрощены, настоящие не соответствуют шаблону и их нелегко перечислить.)

Основная проблема заключается в том, что интерфейс не может определить по URI запроса, должен ли он инициировать вход в систему. Он должен быть реактивным, проксировать запрос на серверную часть и проверять код ответа. Код 401 должен заставить клиента войти в систему, но любой другой ответ должен быть возвращен как есть.

Из-за этого я не могу поместить свою логику авторизации в access_by_luaблок, поскольку они выполняются на этапе доступа до того, как запрос будет отправлен в восходящий поток (бэкэнд).

Я пробовал переместить свою логику в фазу содержания, используя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?

Есть ли лучший подход, который мне следует использовать?

0 ответов

Я закончил настройку шаблонов URL-адресов, используемых в бэкэнде, чтобы можно было заранее различить частные и общедоступные URL-адреса. Тогда логика внешнего интерфейса становится простой:

  • запрос на общедоступный ресурс: прокси на бэкэнд
  • запрос на закрытый ресурс, без заголовка авторизации: возврат 401
  • запрос на частный ресурс с заголовком авторизации: прокси на бэкэнд

Я не знаю, возможен ли мой исходный вопрос (сначала проксирование, а затем принятие решения на основе кода ответа) в OpenResty. Но в конечном итоге я думаю, что новый подход в любом случае чище.

Другие вопросы по тегам