«Так… мне нужна простая авторизация. Какая-нибудь админская роль, и может роль редактора/модератора. Сейчас погуглим. О! Для laravel уже есть готовые пакеты! zizaco/entrust, spatie/laravel-permission и другие! Давай выберем какой-нибудь!»
Примерно так все и происходит. Потом миграция пакета добавляет в базу 5 табличек для хранения ролей, пермишенов и их отношений. Все правила авторизации, такие как роли 'admin' и 'editor' могут делать 'edit posts', хранятся в этих таблицах. Обычно в проекте много копий базы данных. Копии разработчиков, тестовая база(ы) и продакшен. В итоге все эти правила авторизации вынуждены синхронизироваться между базами данных.
Я встречал пару проектов где была одна главная копия правил в базе данных продакшена и остальные все копировали оттуда.
Идея использование Seeder класса(пример) намного лучше. Нужно только запустить
php artisan db:seed AuthSeeder
и у вас свежая версия правил в базе данных. Таким образом, этот seeder класс становится неким Single Source Of Truth. Хорошо, но в этом подходе все еще много неудобств:
- Seeder должен быть довольно умным, чтобы не просто создавать роли и пермишены и связи между ними, но и синхронизировать старые версии. Т.е. удалить или создать связи между ролями и пермишенами если надо.
- Правила хранятся в базе и необходима постоянная синхронизация между ними. Каждое изменение требования вида «редакторы не должны теперь редактировать посты, только публиковать их» приводит к изменению в seeder'е, сихронизации кодобазы через гит или как-нибудь, и «НЕ ЗАБЫТЬ ЗАПУСТИТЬ AuthSeeder!»
- Правила авторизации могут быть сложными. Например публикация может быть отредактирована не только редакторами или админами, но и автором этой публикации. Поэтому вместо простого middleware:
['middleware' => ['permission:edit posts']]
разработчики должны использовать стандартную авторизацию laravel:
class PostPolicy
{
public function edit(User $user, Post $post)
{
return $user->id == $post->owner_id
|| $user->hasPermissionTo('edit posts');
}
}
Так может самый простой путь не самый лучший?
Это только выглядит просто: поставить пакет, запустить готовую миграцию и поехали. С точки зрения долговременной поддержки проекта это не лучший выбор.
Попробуем проанализировать что обычно проектам нужно? Простая ролевая система. Почти всегда одна роль на юзера. Администратор. Ну может еще редактор или модератор. И эти роли имеют некие пермишены. Пойдем самым прямым путем! Добавим новое поле в таблицу users! is_admin или role. Потом пару методов-хелперов в класс User:
class User
{
public function isAdmin(): bool {...}
public function isEditor(): bool {...}
}
Теперь пермишены. Laravel предоставляет два основных метода их описания: Gates и Policies. Я буду использовать gates(тут еще небольшой трюк с функцией в переменной, но для любителей функционального программирования это и не трюк вовсе):
$isAdmin = function (User $user) {
return $user->isAdmin();
}
$isEditorOrAdmin = function (User $user) {
return $user->isAdmin() || $user->isEditor();
}
Gate::define('foo-permission', $isAdmin);
Gate::define('bar-permission', $isAdmin);
Gate::define('editor-permission', $isEditorOrAdmin);
// Complex permission
Gate::define('edit-post', function(User $user, Post $post) {
return $user->id == $post->owner_id
|| $user->isAdmin();
});
Если проекту нужно несколько ролей на пользователя, то просто добавляем таблицу user_roles и изменяем методы-хелперы класса User. Содержимое seeder класса для *trust пакетов и этой code-based авторизации практически идентично! Но правила теперь просто хранятся в коде и нет необходимости постоянно синхронизировать их в базах данных.
Я не хочу сказать, что эти пакеты бесполезны. Этот подход весьма полезен в проектах со сложной системой авторизации, где клиент сам хочет настраивать роли впоследствии. А еще есть проекты с динамическими пермишенами. Пример: форум с подфорумами. Каждый подфорум может иметь своих модераторов, каждый модератор обладает определенными администратором правами на этом подфоруме. Еще пример — telegram и его группы. Там тоже самое. Таким проектам действительно необходима сложная, хранимая в базе данных, система авторизации со всеми ее проблемами. Но большинству других — нет.
Ситуация с пакетами для laravel становится похожей на ситуацию с компонентами для Delphi(старички помнят). Пакеты ставят не раздумывая — нужны реально или нет.
Так, мне бы тут в своем проекте посчитать $a + $b. Нет ли какого-нибудь laravel-sum пакета?
P.S. Прошу прощения за «пермишены», но хорошего точного перевода я не нашел.
Автор: Adelf