Учебная задача для Senior Backend Developer: изощрённая проверка прав доступа

Простейшая проверка  на авторизацию: if (!empty($_SESSION['userid'])) … А если нужно сложнее? if ($user->isAdmin()) … А ещё сложнее?

Какие задачи решают программисты backend в реальных проектах? Вопрос с webmentor.pro

 

Здесь не будет никаких пошаговых инструкций, подсказок и секретов. Это реальная постановка задачи на создание системы авторизации, которая уже была полностью реализована в проекте Icons8, где я работаю Web Architect and Backend Developer. Цель: показать, насколько сложными могут быть системы проверки прав доступа в реальных программных продуктах. Каждый, кто полностью реализует подобную систему самостоятельно, претендует на должность Senior Backend Developer.

Текущая реализация основана на PHP и фреймворке Yii 1.x, но может быть повторена на любом другом языке и фреймворке, а также без фреймворков.

if (\Yii::app()->authManager->isAllowed($icon, Icon::FORMAT_SVG)) ...

Требования

Базовая сущность, доступ к которой должен быть ограничен — иконка, это небольшое графическое изображение в формате SVG (пример).

Требования к логике авторизации исходят из бизнес-модели Icons8 (с упрощениями), которая совпадает с логикой платформ для работы с платным цифровым контентом, например фото-стоков:

  1. иконка имеет атрибуты: дата создания, статус («Опубликована»/»Не опубликована»), категория
    • не опубликованные иконки недоступны никому
    • иконки категории Very Basic и Logos доступны всем и всегда, даже анонимным посетителям
  2. Пользователи могут купить лицензию
    • у лицензии есть дата окончания действия
    • пользователю доступны только те иконки, которые были созданы до даты окончания лицензии; эти иконки остаются доступными, даже если дата окончания лицензии уже истекла
  3. Пользователи могут арендовать иконки до определённой даты
    • у соглашения на аренду есть дата окончания действия
    • пользователю доступны все иконки, пока дата окончания соглашения не истекла; после окончания действия соглашения пользователю становятся недоступными даже те, что он уже использовал
  4. Пользователи могут купить отдельные иконки
    • купленные иконки остаются доступными без ограничения по времени
  5. Пользователи могут получить в подарок один или несколько наборов иконок, которые могут быть изменены модераторами сервиса (например, набор с иконками видов спорта для Олимпийских Игр 2016 в Рио дополнялся ежедневно)
    • у каждого набора есть дата окончания действия, но она может быть не установлена; у набора есть статус («Опубликован»/»Не опубликован»)
    • если у набора есть дата окончания действия, то иконки в составе набора будут доступны, пока она не истекла
    • иначе (если у набора не установлена дата окончания действия), то иконки будут доступны всегда
    • правила предоставления доступа для иконок набора распространяются только если набор опубликован
    • один набор может быть подарен нескольким пользователям (в терминах реляционных баз данных это отношение «многие-ко-многим«)

Базовые сущности

  1. Иконка
  2. Пользователь, включая анонимного посетителя
  3. Лицензия (для упрощения — не более одной лицензии на пользователя)
  4. Соглашение на аренду (для упрощения — не более одного соглашения на пользователя)
  5. Список купленных иконок
  6. Наборы иконок для подарков
  7. Полученные подарочные наборы иконок

Короткая постановка задачи

  • если иконка доступна, то пользователь получает векторное изображение иконки в формате SVG
  • если иконка недоступна, то пользователь получает растровое изображение с наложенными водяными знаками в формате PNG

Вот такая головоломка.

Задача Senior Backend Developer - разработать модель данных, обеспечить надёжность работы, безопасность доступа, высокую производительность, сохраняя понятность кода

Задача Senior Backend Developer — разработать модель данных, обеспечить надёжность работы, безопасность доступа, высокую производительность, сохраняя понятность кода

С чего бы ты начал решение?

Если тебе интересна эта задача в качестве учебной в рамках самообучения профессии Backend Developer — я готов проверить твои решения (модель, код, логику, тесты). Отвечу здесь в комментариях и лично на любые вопросы, которые тебе потребуются по реализации.
Рекомендую начать с самых простых проверок. Например, в следующем порядке:

  1. сделай в первой версии только проверку на доступность иконок Very Basic и Logos всем, включая анонимов
  2. проверку на доступность отдельных купленных иконок
  3. проверку на доступность иконок по лицензии
  4. проверку на доступность иконок по соглашению об аренде
  5. проверку на доступность иконок из подарочного набора

Твой код может быть далёк от идеала, громоздкий, работать с ошибками, не оптимально, без тестов. Не требуется веб-интерфейс (вёрстка, авторизация, админка). Всё может быть реализовано только через JSON API или в выводом прямо в консоль. В начальных версиях всё может быть настолько костыльно и велосипедно, насколько ты сам это можешь это себе позволить.

# черновая версия, не проверялась на работоспособность
# запускать через консоль
# php script.php <имя иконки>

$db = new mysqli("localhost", "username", "pass", "databasename");

$iconName = $argv[1];

/*
CREATE TABLE `icon` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(255) NOT NULL,
  `category` VARCHAR(255) NOT NULL,
  `created_ts` INT(11) NOT NULL,
  `svg_filepath` VARCHAR(255) NOT NULL,
  `png_filepath` VARCHAR(255) NOT NULL,
  PRIMARY KEY (`id`),
  INDEX `idx_icon_name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
*/
$stmt = $db->prepare("SELECT id, name, category, created_ts, svg_filepath, png_filepath FROM icon WHERE name = ?");
$stmt->bind_param('s', $iconName);
$icon = $stmt->execute();

if ($icon && ('Logos' == $icon['category'] || 'Very Basic' == $icon['category']))
{
    echo 'Иконка ', $icon['name'], ' доступна в формате SVG: ', $icon['svg_filepath'];
} else
{
    echo 'Иконка ', $icon['name'], ' не доступна в формате SVG, используй PNG: ', $icon['png_filepath'];
}

Своё финальное решение, реализованное по правилам S.O.L.I.D, DRY, KISS, YAGNI, по технологии разработки TDD с помощью модульных и интеграционных тестов, оформленное согласно рекомендациям PSR — это ценный пункт в твоём портфолио. Такое решение будет ценным даже без внешней красивости. Просто потому что в работе Backend Developer мало внешней красоты. Задача Senior Backend Developer — разработать модель данных, обеспечить надёжность работы, безопасность доступа, высокую производительность, сохраняя понятность кода.

«Какие задачи решают программисты backend в реальных проектах?»

Возвращаясь к началу статьи. Задач на самом деле очень много. Описанный выше пример задачи взят из моей практики, он включает в себя:

  • модель для хранения информации в базе данных
  • логику прав доступа
  • покрытие тестами
  • генерацию PNG с водяными знаками
  • выдачу данных через XML/JSON RPC/REST API (пример реализации api.icons8.com)
  • оптимизацию по скорости — при такой сложной модели на каждую иконку может быть до 10 запросов в базу данных на проверку по всем критериям

Со списком задач по веб-разработке можно ознакомиться в статье Как строится современное веб-приложение. Другие темы учебных задач я перечислял в статье Идеи для учебных проектов по веб-программированию.

Павел Волынцев

Уже более 15 лет занимаюсь разработкой веб-проектов. Fullstack Senior Developer. IT евангелист — доношу свет знаний об информационных технологиях. Профессиональные цели: Дать людям возможность дать людям больше.

Читайте также:

  • Обещаю сделать видео-разбор первого полного решения, которое мне пришлют. Публично или анонимно, то есть с указанием или без указания автора. Это будет полезно всем — и автору, и читателям.
    Если у статьи будет 100 лайков или перепостов, то я сделаю полный пошаговый видео-тьюториал с исходными кодами.
    Поделись ссылкой с друзьями, если ты хочешь быстрее научиться программировать на уровне Senior Backend Developer.

  • Крутая задача. На таком учиться интересно, а не на «Базе данных для школьной библиотеки», как нас учили.

    • Спасибо за оценку! Задачи про библиотеку и видео-прокат встречаются чаще, это точно.