Учебная задача для Senior Backend Developer: изощрённая проверка прав доступа
Простейшая проверка на авторизацию: if (!empty($_SESSION['userid']))
… А если нужно сложнее? if ($user->isAdmin())
… А ещё сложнее?
Здесь не будет никаких пошаговых инструкций, подсказок и секретов. Это реальная постановка задачи на создание системы авторизации, которая уже была полностью реализована в проекте Icons8, где я работаю Web Architect and Backend Developer. Цель: показать, насколько сложными могут быть системы проверки прав доступа в реальных программных продуктах. Каждый, кто полностью реализует подобную систему самостоятельно, претендует на должность Senior Backend Developer.
Текущая реализация основана на PHP и фреймворке Yii 1.x, но может быть повторена на любом другом языке и фреймворке, а также без фреймворков.
if (\Yii::app()->authManager->isAllowed($icon, Icon::FORMAT_SVG)) ...
Требования
Базовая сущность, доступ к которой должен быть ограничен — иконка, это небольшое графическое изображение в формате SVG (пример).
Требования к логике авторизации исходят из бизнес-модели Icons8 (с упрощениями), которая совпадает с логикой платформ для работы с платным цифровым контентом, например фото-стоков:
- иконка имеет атрибуты: дата создания, статус («Опубликована»/»Не опубликована»), категория
- не опубликованные иконки недоступны никому
- иконки категории Very Basic и Logos доступны всем и всегда, даже анонимным посетителям
- Пользователи могут купить лицензию
- у лицензии есть дата окончания действия
- пользователю доступны только те иконки, которые были созданы до даты окончания лицензии; эти иконки остаются доступными, даже если дата окончания лицензии уже истекла
- Пользователи могут арендовать иконки до определённой даты
- у соглашения на аренду есть дата окончания действия
- пользователю доступны все иконки, пока дата окончания соглашения не истекла; после окончания действия соглашения пользователю становятся недоступными даже те, что он уже использовал
- Пользователи могут купить отдельные иконки
- купленные иконки остаются доступными без ограничения по времени
- Пользователи могут получить в подарок один или несколько наборов иконок, которые могут быть изменены модераторами сервиса (например, набор с иконками видов спорта для Олимпийских Игр 2016 в Рио дополнялся ежедневно)
- у каждого набора есть дата окончания действия, но она может быть не установлена; у набора есть статус («Опубликован»/»Не опубликован»)
- если у набора есть дата окончания действия, то иконки в составе набора будут доступны, пока она не истекла
- иначе (если у набора не установлена дата окончания действия), то иконки будут доступны всегда
- правила предоставления доступа для иконок набора распространяются только если набор опубликован
- один набор может быть подарен нескольким пользователям (в терминах реляционных баз данных это отношение «многие-ко-многим«)
Базовые сущности
- Иконка
- Пользователь, включая анонимного посетителя
- Лицензия (для упрощения — не более одной лицензии на пользователя)
- Соглашение на аренду (для упрощения — не более одного соглашения на пользователя)
- Список купленных иконок
- Наборы иконок для подарков
- Полученные подарочные наборы иконок
Короткая постановка задачи
- если иконка доступна, то пользователь получает векторное изображение иконки в формате SVG
- если иконка недоступна, то пользователь получает растровое изображение с наложенными водяными знаками в формате PNG
Вот такая головоломка.
С чего бы ты начал решение?
Если тебе интересна эта задача в качестве учебной в рамках самообучения профессии Backend Developer — я готов проверить твои решения (модель, код, логику, тесты). Отвечу здесь в комментариях и лично на любые вопросы, которые тебе потребуются по реализации.
Рекомендую начать с самых простых проверок. Например, в следующем порядке:
- сделай в первой версии только проверку на доступность иконок Very Basic и Logos всем, включая анонимов
- проверку на доступность отдельных купленных иконок
- проверку на доступность иконок по лицензии
- проверку на доступность иконок по соглашению об аренде
- проверку на доступность иконок из подарочного набора
Твой код может быть далёк от идеала, громоздкий, работать с ошибками, не оптимально, без тестов. Не требуется веб-интерфейс (вёрстка, авторизация, админка). Всё может быть реализовано только через 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 запросов в базу данных на проверку по всем критериям
Со списком задач по веб-разработке можно ознакомиться в статье Как строится современное веб-приложение. Другие темы учебных задач я перечислял в статье Идеи для учебных проектов по веб-программированию.