Смена роли и удаление пользователя

Добавление роли пользователя. Установка роли по умолчанию при регистрации и команда смены роли администратором. Команда удаления неактивного пользователя.

  • 00:00:24 Работа с ролью
  • 00:01:21 Создание и изменение
  • 00:02:52 Объект-значение Role
  • 00:03:33 Смена роли пользователя
  • 00:05:45 Удаление пользователя
  • 00:08:23 Удаление только неактивных
  • 00:09:18 Инкапсуляция проверки
  • 00:12:16 Архитектура модуля аутентификации

В следующем эпизоде мы подключим БД и добавим сохранение наших сущностей. И далее уже напишем контроллеры.

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

Спасибо. Очень хорошо.

Ответить
Bondarenko Alexandr

Спасибо, Дмитрий! Интересен такой момент: вы неоднократно упоминали о подходе Test First. При разработке задачи, к примеру, создания эндпойнта изменения пароля пользователя, на ваш взгляд, следует вначале разработать сценарии взаимодействия с этим эндпойнтом в тестах, а уж затем разработать модульные тесты для проверки метода changePassword у агрегата пользователя, или наоборот, разработать модульные тесты для changePassword, реализовать код для прохождения этих тестов, а уж затем разрабатывать тесты для взаимодействия с эндпойнтом изменения пароля? Или, может быть, какой-то третий вариант?

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

Всегда лучше делать так, как будет удобнее.

Если уже есть полные требования к эндпойнту со стороны заказчика, то их можно сразу описать в приёмочных или функциональных тестах и пока эти невыполняющиеся тесты пометить игнорируемыми. А потом реализовать всё в коде, чтобы они прошли.

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

Ответить
Сарибжанов Ильдар

Спасибо за урок. У меня вопрос не имеющий отношения к программированию =) Согласно GDPR, пользователь должен иметь возможность удалять данные о себе целиком с сервиса. И как тогда решать проблему удаления? Нам не нужны висячие транзакции, но и удалить их нельзя. Как это решается у больших мальчиков? =)

Ответить
Bondarenko Alexandr

Корпоративная тайна)

Ответить
Сарибжанов Ильдар

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

Ответить
Алексей

Очень просто, все данные заменяются, например фио на удаленный пользователь номер такойто, телефоны и емейлы на фейки и все.

Ответить
BATPYIIIKOB

Всё верно - данные обезличиваются, можно сделать через хеш

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

Если используются хранилища вроде Kafka без возможности редактировать старые записи, то для слишком чувствительных данных обычно вместо них записывают значения, зашифрованные ключом, который хранится отдельно у каждого пользователя. Потом просто удаляют этот ключ.

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

Дмитрий. Здравствуйте.

Очень было бы интересно рассмотреть правильную архитектуру и работу с: городами, областями, странами, геокоординатами, улицами и т. д.

Здесь волнует такой вопрос, что гео используется во многих сервисах сайта. Получается это гео надо выносить в свой сервис. Так же не понятно как лучше хранить данные: id, координаты, строка. Какие данные можно получать по связям, а какие надо хранить в сущности.

Очень благодарен был бы за рассмотрение этого подхода и работу со сторонними сервисами типа Яндекс, Гугл и др.

А так же загрузку использование своего общего аватара (на подобии gavatar). Но это в принципе понятно. Но тоже интересно.

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

Получается это гео надо выносить в свой сервис.

Города и страны можно вынести оидельно, а всем сущностям присваивать только их идентификаторы.

Так же не понятно как лучше хранить данные.

Если нужны просто координаты, то можно записывать в new Coordinate(lat, long)

Какие данные можно получать по связям, а какие надо хранить в сущности.

В доменной сущности нужно хранить только необходимый минимум. Ей хватит только идентификатора.

Связи обычно нужны только для отображения на фронтенде. Поэтому для отображения удобно делать отдельные голые SQL-запросы со всеми нужными нам JOIN-ами. До этого дойдём когда помимо Command начнём делать Query.

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

Благодарю!

Ответить
Sergei

Дмитрий, а можно вопрос: вы изменяете историю коммитов или ребейз делаете? У меня гиткракен иногда смещает историю при ваших обновлениях на ориджине. Мне приходится резет делать на мастер/ориджин из-за конфликта с текущей одной единственной веткой :)

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

Да, старые коммиты понемногу исправляются интерактивным ребейзом.

Ответить
Sergei

Спасибо за ответ. Я думал у меня гиткракен глючит :)

Ответить
Андрей

У меня такой вопрос. Допустим, в будущем нам понадобится возможность для каждого товара аукциона настроить видимость по ролям. То есть только пользователи с определенными ролями могут просматривать товар, а с какими именно ролями — настраивается в каждом конкретном товаре. Получается, что где-то в модуле Auction будет свой класс Role или Roles, в котором тоже будут использоваться константы USER и ADMIN.

Как в этом случае поступить? Можно ли вынести эти константы в общий интерфейс, например RoleInterface, и сделать так, чтобы классы в обоих модулях реализовывали этот интерфейс? Или константы в каждом классе должны быть свои? Тогда где их потом сопоставлять?

Если вариант с общим интерфейсом подходит, то где его разместить? Если оставить его в модуле Auth, то получится, что класс одного модуля реализует интерфейс из другого, и модули как бы перестают быть независимыми. Или сделать отдельную папку Interface за пределами модулей и все общие интерфейсы выносить туда?

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

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

Ответить
Андрей

С ролями действительно получился неудачный пример. Мой вопрос был более общий: насколько корректно, когда классы в разных модулях реализуют какой-то единый интерфейс. Получается, что все-таки так делать не надо? И даже если в разных модулях задействованы одни и те же константы, то они всё равно должны быть у каждого модуля свои. А снаружи уже всё это сопоставляем. Верно?

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

Если это просто общий код, то спокойно его используем вроде нашего Flusher из корня. Если же нужна именно логика из другого модуля, то как компромисс можем у одного объявить интерфейс, а снаружи к нему реализовать адаптер. Но корректнее это будет реализовать в виде обмена сообщениями через очередь.

Ответить
Андрей

Понял, спасибо

Ответить
Николай

Добрый день! Отличный урок, но непонятно, как все-таки правильно разбивать логику с уже удаленным пользователем. Например у нас есть метод подтверждения пользователя по смс или звонку, а пользователя мы удалили. Где мы делаем проверку?

  1. В самой сущности пользователя и запрещаем ему confirm,
  2. В Handler перед использованием confirm.
  3. В контроллерах

И вопрос такого же характера. Есть у нас например роли User и Manager. Manager может создавать и удалять пользователя, но пока мы не делаем RemoveByManager, а просто Remove. В этом случае, я так понимаю все надо оставлять в Контроллерах приложения, а задача нашего модуля только в том, чтобы предоставить базовый функционал, а приложение уже само решает как им распоряжаться?

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

Например у нас есть метод подтверждения пользователя по смс или звонку, а пользователя мы удалили.

Если мы его действительно удалили, то и токен подтверждения удалится из БД. И пользователь и так не найдётся по токену.

Если же мы не удалили пользователя, а просто заблокировали или архивировали, то тогда ближе всего будет сделать проверку прямо в его методе confirm.

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

В этом случае, я так понимаю все надо оставлять в Контроллерах приложения...

Да, обычно при простом RBAC роли проверяют в контроллерах. Отдельные команды вроде RemoveByManager нужны если там что-то будет отличаться.

Ответить
Руслан

Дмитрий, можно вопрос, будете учитывать случай когда у пользователя одновременно две роли (продавец и покупатель), сможете рассмотреть в одном из следующих эпизодов внедрение RBAC, ABAC или другой модели ролей/разрешений которая лучше для этого подходит? Спасибо.

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

Продавец, покупатель и другие подобные бизнес-роли как раз можно делать на доменном уровне вроде ABAC. Например, проверками в модуле магазина, что есть сущность "Продавец" или сущность "Покупатель" с таким ID пользователя. А в RBAC указывать только глобальные роли вроде user и admin для всей системы.

А если это делать в RBAC именно ролями продавца и покупателя, то тогда можно сделать привязку пользователю и помещение в токен не одной роли, а массива.

Ответить
Фирзар

Добрый день. В приложении имеется компании, магазины и товары. Пользователь должен работать только с теми товарами которые имеются в магазине его компании (руководитель конкретной компании), или только конкретного магазина (руководитель конкретного магазина). Какой паттерн/методику посоветуете?

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

Если владельцев может быть несколько, то добавить many-to-many связи вроде company_owners(company_id, user_id) и shop_owners(shop_id, user_id). И уже по ним вычислять доступы.

Ответить
Петр

Добрый день, подскажите, не совсем понял вот этот фрагмент кода с удалением:

$user->remove();
$this->users->remove($user);

Будет ли в следующих уроках какая-то проверка в методе $this->users->remove(), чтобы было нельзя удалить пользователя без проверки на удаление в $user->remove() ?

Пока складывается впечатление, что можно удалить активного пользователя просто проигнорировав проверку.

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

Метод $user->remove() проверяет бизнес-правила удаления и в будущем может генерировать событие удаления.

Проверять на бизнес-правила удаления в самом репозитории $this->users->remove($user) не очень уместно, так как репозиторий нам нужен именно для физического удаления записи из БД.

Так что риск есть, но лучше оставить всё как есть.

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

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

Yandex
MailRu
GitHub
Google