Перейти к содержимому

11.03.2015

7

Прозрачная авторизация сервисов в гетерогенной среде на базе Nginx/LUA

Я давно уже полюбил связку Nginx и LUA. И сегодня хочу рассказать про один вариант использования этих инструментов.

Суть задачи/проблемы:
Представьте, что в вашей информационной системе есть набор различных сервисов, с которыми могут взаимодействовать клиентские приложения. Конечно же, доступ к системе и к сервисам, в частности, разрешается после авторизации.
Все сервисы общаются с клиентами по разным протоколам (HTTP REST API, SOAP, XML-RPC, WebSocket, WAMP, GET/POST запросы и так далее) и даже написаны на разных языках.

Вопрос: как минимальными усилиями сделать, чтобы доступ к любым сервисам был возможен только авторизованным пользователям?

Рассуждения и возможные способы решения:
Первое, что приходит в голову — это написать модуль авторизации для каждого сервиса и пусть сервис сам проверяет все входящие запросы. Минусы этого подхода достаточно очевидны:

  • Вам придется, как минимум, написать ровно столько реализаций модуля авторизации, сколько у вас различных языков, на которых написаны сервисы.
  • И в дальнейшем вам придется поддерживать все эти модули.
  • Так же, для начала придется четко описать и указать как должна быть устроена авторизация, иначе разработчики на разных языках напишут свои собственные велосипеды в соответствии со своим личным чувством прекрасного.

Другой вариант — это написать один сервис, который будет отвечать за авторизацию и проксировать все запросы уже на соответствующие сервисы. Отличный вариант! Но писать с нуля такой сервис, попутно решая задачи балансировки, масштабируемости, отказоустойчивости и прочие — совсем не хочется. У нас же есть Nginx и LUA!

Основная идея такого решения в следующем:
Поскольку REST/WebSocket/WAMP/SOAP/XML-RPC и прочее — это все подходы/протоколы, основанные на HTTP, Nginx будет являться входной точной всех запросов, далее, на этапе обработки запроса выполняется lua скрипт, который проверяет валидность сессии, например в базе данных, и если все ок, nginx проксирует запрос на соответствующий сервис. Так же мы запрещаем доступ к сервисам извне. В случае, если все сервисы живут в рамках одного сервера, переводим их на прослушивание только на localhost’е. Так же отмечу, что LUA модуль работает поверх NGINX cosockets & subrequests с неблокирующим I/O.

nginx lua architecture

Вот примерный конфиг nginx:

И вот каким может быть lua-обработчик запросов. В данном примере происходит подключение к локальному MySQL серверу, и выполняется запрос на проверку наличия в БД сессии пользователя с такого IP-адреса и с таким идентификатором сессии. В случае ошибки на любом шаге, возвращается статус «403: Forbidden». Пример упрощен, чтобы показать суть, и не стоит обращать внимание на тему SQL-инъекций и прочих штук.

Можно легко адаптировать данный lua-скрипт, чтобы он ходил в memcache, redis, postgres или даже просто сам обращался по сокету или вебсокету на какой-то внутренний сервис. На openresty.org можно посмотреть на большой список уже написанных модулей.
Так же можно (и даже нужно) сделать, чтобы все клиентские приложения общались с фронтом сервисов через https, а запросы на непосредственно сервисы nginx будет проксировать по http, тем самым снижая накладные расходы и избавляя сервисы от необходимости поддержки SSL/TLS.

Вот такое решение. Надеюсь, оно кому-то пригодится, или, как минимум, натолкнет на полезные мысли и решения.

Узнайте больше из Web-Разработка
  • Sergei Seleznev

    Надо клиентов подключать через единую точку входа — например ESB %)

    • Нуу ESB — это всего лишь общая шина данных. А доступ-то все равно осуществляется через какие-то сервисы. Другое дело, что некоторые реализации, например Oracle SOA Suite, умеют прозрачно передавать токены авторизации между вызовами сервисов, медиатором и т. д. и разработчикам клиентских приложений не надо об этом задумываться.

      • Sergei Seleznev

        На шине организуется авторизованный доступ к сервисам — в одной точке, аля SSO — SING SIGN ON %)

  • Yura Vdovytchenko

    натолкнуло! пригодилось:) прочтя Ваш пост, написал авторизатор auth-dav и загорелся проектом опенсорс облачных хранилищ на чистой связке nginx+lua «ITCOD-DISK». Спасибо:)

  • Артем

    Я полностью согласен с тем, что разработчикам клиентских приложений не нужно об это задумываться. Однако знание базы Nginx/LUA будут всегда полезны.

    С уважением,
    Артем
    http://ru.intechcore.com/

  • Alex

    А мне в глаза бросилось — использование необработанного значения из HTTP запроса в SQL запросе («x-user-session»). Или я просто не верно понял Lua код?