Задонатить и смотреть →
Открой безлимитный доступ к 100+ полезных скринкастов и получай скидки на все предстоящие мероприятия

Страница входа и Query-модель

Продолжаем интеграцию. Когда у нас готовы сущности и репозитории создадим сам компонент OAuth-сервера. Для него сгенерируем файлы ключей и сделаем их деплой из Jenkins через Docker Secrets. Сделаем страницу входа и контроллер для генерации и обновления токенов. Все контроллеры покроем функциональными тестами.

По аналогии с Command добавим Query-модель на DBAL для выполнения запросов на чтение данных из модуля. И заодно рассмотрим, как можно избавиться от вызова синглтона SentrySDK в коде наших сервисов и экшенов:

  • 00:00:43 - Работа с Authorization Server
  • 00:05:59 - Ключи для подписи и шифрования
  • 00:07:55 - Регистрация Encryption Key
  • 00:09:50 - Использование Secrets в Docker
  • 00:14:28 - Деплой файлов из Jenkins
  • 00:16:38 - Создание авторизационного сервера
  • 00:20:43 - Функциональные тесты авторизации
  • 00:22:49 - Тестирование HTML-страниц
  • 00:29:41 - Ответ для HTML-страниц
  • 00:30:51 - Вёрстка страницы входа
  • 00:31:59 - Контроллер для входа
  • 00:35:51 - Вынос компонента Sentry
  • 00:38:16 - Избавление от вызова синглтона
  • 00:45:05 - Команды и запросы
  • 00:47:08 - Запрос пользователя по паролю
  • 00:49:25 - Отдельная Query-модель чтения
  • 00:53:04 - Запросы через DBAL
  • 00:55:17 - Реализация формы входа
  • 01:02:22 - Экшен генерации токенов

В следующем эпизоде сделаем аутентификацию для страницы просмотра профиля и добавим Cron-команды в Docker Swarm для очистки старых кодов и токенов.

Скрытый контент (код, слайды, ...) для подписчиков. Открыть →
Дмитрий Елисеев
elisdn.ru
Комментарии (26)
Руслан

Спасибо!

Ответить
Максим (@myks92)

Спасибо!)

Ответить
v

Почему Fetcher из FindIdByCreedintials сам строит запрос в базу данных, а не обращается к UserRepository?

Ответить
Дмитрий Елисеев

Как раз об этом рассказал с 49-ой минуты

Ответить
Александр

Спасибо!

Ответить
fedot

Спасибо!

Ответить
Arunas

Спасибо :)

Ответить
Артем Астапов

Дмитрий, добавляйте пожалуйста ссылки на гайды - например, с сайта developer.okta.com и oauth2.thephpleague.com

Ответить
slo_nik

Добрый вечер, Дмитрий.

Подскажите, пожалуйста, если не использовать docker swarm, можно ли как-то прочитать файлы ключей в контейнере?

Пробовал в docker-compose.yml указать файлы ключей через secrets, но на рабочем сервере не получается прочитать файлы, отказано в доступе.

Права на файлы получаются 0400 и создаются от root.

Я пробовал указать mode в docker-compose.yml, но права на файл не менялись.

secrets:
        - source: db_password
          target: database_password_secret
          mode: 0440
Ответить
Дмитрий Елисеев

Локально мы не используем swarm, но секреты нормально подключаются. Так что странно, что не срабатывает.

Ответить
slo_nik

Да, локально без проблем.

Проблемы на рабочем сервере.

Использование mode не помогло, поискал информацию в инете, но нашёл только то, что эти настройки работают только со swarm-ом, это как бы не полноценная настройка(возможно не так выразился). То есть, как бы я не менял права доступа к файлу через mode, права остаются без изменений.

Вот такими права остаются

-r-------- 1 slonik slonik   1273 мая 30 23:11 phpunit.xml.dist
Ответить
Ярослав

Когда я захожу по адресу localhost:8081/authorize то выбивает ошибку:

Key path "file:///run/secrets/jwt_private_key" does not exist or is not readable

Когда я зашел внутрь контейнера api-php-fpm, то внутри папки /run/secrets вижу такое:

-rw------- 1 1000 1000 1675 Oct 22 12:13 jwt_private_key

-rw-rw-r-- 1 1000 1000 451 Oct 22 12:14 jwt_public_key

Соответственно тесты в файле AuthorizeTest не проходят(там ошибка 500).

И что я не так сделал, я без понятия. Там походу ведь docker-compose должен прокидывать туда эти ключи. Он у меня версии 1.25.0. Может дело в нем?

Ответить
Ярослав

Проблема решена заменой ключей на те, что были в репозитории. Все тесты теперь проходят.

Ответить
Aёct'ann

Проблема в том, что у файла jwt_private_key нет прав на чтение. Когда эти файлы были сгенерированы - у них такие права стоят в целях безопасности. Нужно добавить для этого файла права на чтение, только вот не знаю, группы или для всех... Как вариант:

chmod ugo+r docker/development/secrets/jwt_private.key
Ответить
Максим

Добрый день, и с наступающим новым годом! В данном уроке, Дмитрий, Вы используете чисты Sql. Получается что название таблиц и столбцов помимо маппинга на сущности ещё и будут в каждом таком запросе. Doctrine решает эту проблему с помощью Dql, плюс даёт возможность расширять этот язык. В своем проекте, я как раз пытаюсь уйти от нативного Sql, в пользу языка запросов к доменной модели.

Ответить
Максим (@myks92)

Здравствуйте. Столкнулся инфраструктурной проблемой и ридмоделями.

В объектах домена понятно дело нет всей информации для построения ридмодели.

К примеру нет понятия кем создана заявка - человеком/ботом. Кто владелец данной заявки, кто редактор.

Но нужна ли она бизнесу? Наверное нет, чем да. Но для построения рид модели понадобилась данная информация.

Как быть?

Единственное что я сейчас вижу это metadata у бизнес объектов куда я могу складировать дополнительную информацию. Создать какой-то отдельный контекст для этого и хранить всё там. Почему отдельный контекст? Потому что это не доменная модель. Бизнесу это не нужно в его контексте. Поэтому и портить доменную модель инфраструктурной частью приложения не хочется. Тогда где же хранить подобную информацию?

Ещё есть кейс - Owner. Когда есть владелец, чего-то и на основании этого надо предоставлять права на редактировании. Опять же это не бизнес требование, а предоставление доступа на уровне приложения. Соотвественно опять не хочется портить бизнес слой контекста. Тогда где хранить?

Хотелось бы услышать Ваши мысли. Благодарю!

Ответить
Дмитрий Елисеев

Проще всего хранить прямо в заявке.

Ответить
Sergey

Добрый вечер.

Вопрос по поводу хранения запросов внутри модуля Auth в папке api/src/Auth/Query

Я так понимаю ответственности (функциональность) классов/интерфейсов находящихся внутри папки api/src/Auth должны быть изолированны в рамках этого модуля Auth и не могут напрямую зависеть от классов и данных других модулей (которые наверняка появятся в проекте в ближайшем будущем).

Отсюда вопрос, если появится sql query который будет содержать к примеру джойны (я понимаю что можно обойтись без джойнов и собирать к примеру в контроллере результат из отельных простых queries, но как показывает практика простой join по производительности чаще всего выигрывает) на таблицы других модулей тогда где их хранить? Ведь папка api/src/Auth/Query уже не подходит в этом случае (как и соответствующая папка в внутри другого модуля), так как query будет зависеть в данном случае от таблиц уже разных модулей.

В каком месте вы бы хранили такие queries?

Заранее спасибо за ваше время!

Ответить
Дмитрий Елисеев

Про это как раз делал доклад про модульное разделение. А в общем да, собирать данные из разных модулей в контроллере. А если нужен обобщающий запрос, то положить в отдельную папку.

Ответить
Sergey

Спасибо за быстрый ответ. Ознакомлюсь с докладом

Ответить
Максим (@myks92)

С позволения Дмитрия добавлю ответ. Суть деления на модули как раз и заключается в том чтобы убрать зависимости между модулями, в том числе и по базе данных. Когда хочется сделать такое - представьте, что это разные базы. Один модуль в Redis, второй в PostgreSQL. Либо вам достался проект, где постепенно переходите с Mysql на PostgreSQL. Если вы организуете связанность по Join таблицы, то вы создали неконтролируемую связь. Завтра кто-то захочет удалить модуль или изменить название таблицы, поменять название столбцов и ваш модуль сломается. Поэтому и предлагается на уровне контроллера делать запрос из разных Query. А с какой базы они работают - нам всё равно. Поэтому лучше использовать разные Query в контроллере или интерфейсы для взаимодействия. Но если всё таки хочется сделать такую Query по каким либо причинам не стоит это делать в папке модуля. Мы иногда такие Query выносим в src/Query. По аналогии stc/Http. Таким образом мы контролируем зависимость.

Ответить
Aёct'ann

Доброй ночи! А почему страница для авторизации сделана на стороне "бэка"? Мы же могли ее сделать на фронте и подгружать из реакта?

Ответить
Дмитрий Елисеев

В OAuth так делают специально для безопасности, чтобы логин и пароль вводили только на сервере аутентификации. Если нужен самый безопасный вариант, то туда стоит перенести также регистрацию и восстановление пароля и защитить все формы от CSRF, чтобы фронтенд и другие клиенты вообще не работали с паролями.

Ответить
Simon

Добрый день, Дмитрий. А можно по подробнее про безопасность? Почему мы не можем генерить форму на реакте?

Ответить
Дмитрий Елисеев

Представьте, что на каком-либо чужом сайте или в чужом мобильном приложении вы нажали "Войти через Google", а вам вместо редиректа оно прямо у себя выведет форму: "Введите сюда свой email и пароль от Google".

Я испугаюсь, что этот сайт может сохранить мой пароль куда-то у себя перед тем, как полезет логинится с этим адресом и паролем по API.

Именно поэтому у большинства OAuth сервисов не включен Password Grant и в API нет никакого адреса входа по паролю. Возможен только вход через оригинальную форму по редиректу. Чтобы программисты других сайтов или приложений не делали свои формы-посредники.

Ответить
Simon

спасибо

Ответить
Зарегистрируйтесь или войдите чтобы оставить комментарий

Или войти через:

Google
GitHub
Yandex
MailRu