Практикум. Реализация двухфакторной аутентификации
Двухфакторная аутентификация указывает, что для входа в си-стему пользователю надо что-то, что он знает (например, пароль), и что-то, что он имеет (например, номер телефона). Двухфактор-ная аутентификация намного лучше просто пароля, поскольку злоумышленнику для получения доступа придется украсть и ваш пароль, и номер вашего телефона.
При планировании реализации двухфакторной аутентифика-ции нужно обработать запрос на генерацию случайного кода, зарегистрировать его в службе входа в систему и отправить сообщение пользователю. Можно добавить код, реализующий эту функциональность, непосредственно в саму службу входа в систему. Это усложняет систему, делает ее более монолитной. Отправка сообщения должна выполняться одновременно с ко-
дом, генерирующим веб-страницу входа в систему, что может привнести определенную задержку. Эта задержка ухудшает качество взаимодействия пользователя с системой. 146Часть II. Паттерны проектирования обслуживающих систем Лучше будет создать FaaS-сервис, который бы асинхронно ге-нерировал случайное число, регистрировал его в службе входа в систему и отправлял на телефон пользователя. Таким образом, сервер входа в систему может просто выполнить асинхронный запрос к FaaS-сервису, который параллельно выполнит относи-тельно медленную задачу регистрации и отправки кода. Для того чтобы увидеть, как это работает, рассмотрим следу-ющий код:
def two_factor(context):
# Сгенерировать случайный шестизначный код code = random.randint(1 00000, 9 99999)
# Зарегистрировать код в службе входа в систему user = context.json["user"]
register_code_with_login_service(user, code) # Для отправки сообщения воспользуемся библиотекой Twillio account = "my-account-sid"
token = "my-token"
client = twilio.rest.Client(account, token) user_number = context.json["phoneNumber"] msg = "Здравствуйте, {}, ваш код аутентификации: {}.".format(user, code)
message = client.api.account.messages.create(to=user_number, from_="+1 20652 51212",
body=msg)
return {"status": "ok"}
Затем зарегистрируем FaaS в kubeless:
kubeless function deploy add-two-factor \
--runtime python27 \
--handler two_factor.two_factor \
--from-file two_factor.py \
--trigger-http
Экземпляр этой функции может асинхронно порождаться из клиентского кода на JavaScript после ввода пользователем пра-Глава 8. Функции и событийно-ориентированная обработка 147вильного пароля. Веб-интерфейс может немедленно отобразить страницу для ввода кода, а пользователь, как только получит код, может сообщить его службе входа в систему, в которой этот код уже зарегистрирован.
Итак, подход FaaS существенно облегчил разработку простого, асинхронного, событийно-ориентированного сервиса, который инициируется при входе пользователя в систему. Событийные конвейеры
Существует ряд приложений, которые, по сути, проще рассма-тривать как конвейер слабо связанных событий. Конвейеры со-бытий часто напоминают старые добрые блок-схемы. Их можно представить в виде ориентированного графа синхронизации связанных событий. В рамках паттерна Event Pipeline узлы соответствуют функциям, а дуги, их соединяющие, — HTTP-запросам или другого рода сетевым вызовам. Между элементами контейнера, как правило, нет общего состоя-ния, но может быть общий контекст или другая точка отсчета, на основе которой будет выполняться поиск в хранилище. Какова же разница между таким конвейером и микросервис-ной архитектурой? Есть два важных различия. Первое и самое главное различие между сервисами-функциями и постоянно работающими сервисами состоит в том, что событийные кон-вейеры, по сути, управляются событиями. Микросервисная архитектура же, напротив, подразумевает набор постоянно работающих сервисов. Кроме того, событийные конвейеры могут быть асинхронными и связывать разнообразные события. Сложно представить, как можно интегрировать одобрение заяв-ки в системе Jira в микросервисное приложение. В то же время нетрудно представить, как оно интегрируется в событийный конвейер.
148Часть II. Паттерны проектирования обслуживающих систем В качестве примера рассмотрим конвейер, в котором исходным событием будет загрузка кода в систему контроля версий. Это событие вызывает пересборку кода. Сборка может занять не-сколько минут, после чего создается событие, инициирующее функцию тестирования собранного приложения. В зависимости от успешности сборки функция тестирования предпринимает разные действия. Если сборка прошла успешно, создается за-явка, которая должна быть одобрена человеком, чтобы новая версия приложения вошла в эксплуатацию. Закрытие заявки служит сигналом к вводу новой версии в эксплуатацию. Если сборка завершилась неудачно, в Jira делается заявка об обнару-женной ошибке, а конвейер завершает работу. Практикум. Реализация конвейера для регистрации нового пользователя Рассмотрим задачу реализации последовательности действий для регистрации нового пользователя. При создании новой учетной записи всегда выполняется целый ряд действий, на-пример отправка приветственного электронного письма. Есть также ряд действий, которые могут выполняться не каждый раз, например подписка на e-mail-рассылку о новых версиях продукта (также известную как спам).
Читать дальше