Русское сообщество разработки на PHP-фреймворке Laravel.
Ты не вошёл. Вход тут.
(Laravel 5.3 и базовая auth)
Есть три таблицы: users, roles и permits.
Первая и вторая, вторая и третья связаны отношениями "многие ко многим".
Задача: для юзера, через назначенные ему роли, выбрать права, которыми он обладает (права назначаются роли).
Делаю так:
// получаем id в таблице roles для пользователя
$roles_id = Auth::user()->roles->pluck('id');
// получаем все права в виде json-массива
$permits = Role::find($roles_id)->permits()->pluck('slug');
// получаем нужный простой массив прав
$permits_array = json_decode($permits, true);
Вопрос:
- можно ли реализовать проще?
- что будет, если ролей у юзера будет несколько? (Пока я прописывал только одну)
Не в сети
можно проще. на правах нет никаких атрибутов кроме слага соответственно заводить под права таблицу нет смысла.
кроме этого нужно иметь возможность задавать отдельные пермишены на пользователе не через группу – быстро понадобится по-быстрому дать пользователю что-нибудь иметь возможность делать лично а не через права группы.
соответственно users и roles оставить, отношение многие-ко-многим оставить, на пользователе и на роли завести поле permissions тип text, содержание – массив в json-е. в модели объявить в $casts: 'permissions' => 'array'
хранить отдельные пермишены текстовыми строками вида "posts.*", "posts.edit". при загрузке пользователя выбирать его роли, объединять пермишены с array_merge, запоминать в тегированном кэше с ключом "users" (сбрасывать по тэгу при изменениях в пользователях). при проверке доступа искать пермишены в кэше или загружать из базы и проверять для "posts.edit" в массиве наличие записей "posts.edit", "posts.*" или "*". соответственно право "*" означает что пользователь – superadmin и может делать всё
как-то так
Не в сети
Я бы роли сделал отдельным полем в users в виде smallint. Иначе на более менее сложном проекте упрешься в кучу ограничений. На очень сложном, я бы и от permit избавился.
А вообще, не лучше использовать готовый популярный пакет, к которому в сети можно найти много готовых рецептов?
Не в сети
зачем smallint? можно просто сделать role_id unsigned int и сделать один-ко-многим на таблицу ролей, но заранее решать что уже точно известны все роли и меняться они никогда не будут – это слишком смело многие-ко-многим – это тоже один из вариантов, мы же не знаем заранее что там в ТЗ. может там прописано что пользователь может принадлежать нескольким группам одновременно?
на более менее сложном проекте упрешься в кучу ограничений
как раз со smallint и упрёшься. ещё забудешь по ходу дела что отдельные значения означают и накосячишь где-нибудь
о, можно ещё надёжнее – завести на пользователе tinyint is_admin! максимальная надёжность и производительность! )))
Не в сети
А вообще, не лучше использовать готовый популярный пакет, к которому в сети можно найти много готовых рецептов?
Проще, однозначно. Он сам создаст нужные сущности и избавит от необходимости поиска решений, а лишнего не потянет.
Вот тут обсуждалась тема.
Не в сети
многие-ко-многим – это тоже один из вариантов
Ну да, только почему так много заказчиков ищут разработчика, который бы завершил их проект, потому что их разработчик "ушел на другой проект", "не смог продолжить по личным причинам" и т.д.? Посмотришь проект - а там такая архитектура, с которой шаг влево не сделать. Пример - нужно показать выборку комментариев к публикациям пользователей с опредленными permissions по определенным странам. Наворотят вот такое, а потом начинаются вопросы на форумах и SO "а как сделать выборку, если у меня many-to-many, дальше hasMany и там еще many-to-many... еще параллельно по many-to-many страны отфильровать?".
о, можно ещё надёжнее – завести на пользователе tinyint is_admin! максимальная надёжность и производительность! )))
KISS. Для большинства приложений нужно 1-3 роли без разделения полномочий, а в полуторах методах, где это используется, можно сделать локальную проверку или дополнительную роль. Но большинство все равно лепят то, что лепит автор. А вот посмотришь код сложных проектов от серьезных ребят, там как раз используешься тот замечательный надежный isAdmin().
Изменено AlexeyMezenin (27.12.2016 08:26:16)
Не в сети
Я бы роли сделал отдельным полем в users в виде smallint. Иначе на более менее сложном проекте упрешься в кучу ограничений. На очень сложном, я бы и от permit избавился.
А вообще, не лучше использовать готовый популярный пакет, к которому в сети можно найти много готовых рецептов?
Я забыл написать что не нужно менять структуру таблиц которые создают Laravel и SleepingOwl.
Вот и использую пакет "Совы", но он не имеет проверок, кто может туда переться, а кто нет. Далее прикручу Sentinel вместо Auth.
Мой вопрос связан с middleware для админки ...
Всем спасибо. (Для многих ролей не обойтись видно без foreach с последующим объединением массивов ...)
Изменено Grumm (27.12.2016 08:28:11)
Не в сети
Grumm, когда всем этим будешь заниматься, создай много ролей и пермитов для тестирования и смотри на количество запросов, которые создает Laravel. В этом тебе поможет Laravel Debugbar.
Не в сети
Вот и использую пакет "Совы", но он не имеет проверок, кто может туда переться, а кто нет.
Разве не имеет? "Сова", вроде, с ролями неплохо работает, или я не так Вас понял?
Не в сети
Grumm, когда всем этим будешь заниматься, создай много ролей и пермитов для тестирования и смотри на количество запросов, которые создает Laravel. В этом тебе поможет Laravel Debugbar.
Эта панелька внизу уже стала родной на локали! )
Не в сети
Grumm пишет:Вот и использую пакет "Совы", но он не имеет проверок, кто может туда переться, а кто нет.
Разве не имеет? "Сова", вроде, с ролями неплохо работает, или я не так Вас понял?
Это админка. Она не имеет системы авторизации. Возможно вы путаете с Sentinel.
Не в сети
Может кому надо будет:
// получаем права пользователя в виде массива
$roles_id = Auth::user()->roles->pluck('id');
$result = array();
// перебираем полученные id
foreach ($roles_id as $item)
{
$permits = Role::find($item)->permits()->pluck('slug');
$permits_array = json_decode($permits, true);
// результирующий массив, в котором собраны все права закрепленные за юзером, исключая повторяющиеся.
$result = array_unique(array_merge($result, $permits_array));
}
/**
* Таким образом можно проверять юзера на право что либо совершать в админке,
* присваивая ему любое количество ролей, с любым набором прав.
*/
Не в сети
Может кому надо будет:
Присвой пользователю 3-4 роли и несколько пермитов и посмотри сколько запросов в БД создаст код.
Не в сети
Grumm пишет:Может кому надо будет:
Присвой пользователю 3-4 роли и несколько пермитов и посмотри сколько запросов в БД создаст код.
Сегодня мозги уже кипят. Завтра буду гонять тестами ...
Не в сети
Это админка. Она не имеет системы авторизации. Возможно вы путаете с Sentinel.
Я не путаю, системы авторизации не имеет, верно, но с auth и ролями работает легко.
Не в сети
Я не путаю, системы авторизации не имеет, верно, но с auth и ролями работает легко.
Аха, работает. Админ, не админ. Это всё.
Скажите как по вашему разрешить к примеру смотреть и банить юзеров, но не удалять их и не править им профиль? И не лезть в другие разделы админки?
Не в сети
Ну лично у меня, например, контент-менеджер не имеет доступа к редактированию аккаунтов, но публикует новости. Это на уровне разделов, вроде бы, можно и на уровне методов, но сам пока не проверял. Сейчас работаю над тем, чтобы в самой админке создать раздел, в котором админ сможет работать с ролями, определяя им права в "Сове", а политика будет работать с этой моделью.
Изменено Androbim (28.12.2016 18:24:21)
Не в сети
Присвой пользователю 3-4 роли и несколько пермитов и посмотри сколько запросов в БД создаст код.
Присвоил. Четыре роли, у каждой по четыре права. Запросов 20, время 90 ms. В том числе запросы самого фреймворка (5 запросов).
В общем: разных админов не будет очень много (да хоть 100) и толпой они не ходят. Если в админку полезут хакеры, отработает трейт по ограничению запросов с одного Ip. Конечно запросов много, но или универсальность, или оптимальность. Почему я и вынес вопрос - "как сделать проще ...".
Изменено Grumm (29.12.2016 18:01:29)
Не в сети
Запросов 20
Дак приложение будет эти 20 (дальше больше) запросов на каждый запрос запускать. Проверка ведь каждого пользователя будет идти? Если нет, то какой смысл вообще в использовании ролей и пермитов?
К слову, isAdmin(), над которым выше посмеялись, вообще не создаст ни одного лишнего запроса, т.к. будут использоваться данные из запроса в users, который Laravel создает для каждого запроса.
Не в сети
Проверка ведь каждого пользователя будет идти?
С какой стати пользователем переться в админку? Этот посредник работает только для админки. Проверка админ\не админ меня не устраивает. Для этого вообще ничего не надо сочинять ...
Изменено Grumm (29.12.2016 18:26:12)
Не в сети
С какой стати пользователем переться в админку?
Еще раз, тогда какой вообще смысл в пермитах и ролях?
Не в сети
Тема закрыта.
Не в сети
"Ой, всёёё!!!"
Не в сети
Grumm, с таким подходом к разработке далеко не уедешь. Создал совершенно ненужную фичу, с двумя many-to-many - 5 таблиц! Создал без использования жадной загрузки, в итоге 20 совершенно ненужных запросов даже на пустом проекте. Почитай про принцип KISS - Keep it simple stupid.
Не в сети
Я вот не понял, зачем одному пользователю несколько ролей? Ну это ладно, это разработчику виднее - хотя он сильно осложнил себе жизнь. И не только связью "многие-ко-многим", это-то рутина. А шизофреничностью назначения прав. Менеджеру нельзя, бухгалтеру можно, а если он и менеджер и бухгалтер - ему можно или нельзя?
Не проще сделать НОРМАЛЬНЫЙ набор ролей? Если ты главбух - ну и заходи как главбух, а не скрещивай менеджера с бухгалтером.
Но что совсем удручает - какие-то джсон-массивы. Одним банальным SQL-запросом эта задача решается. Кинул запрос - и вуяля: получил права, сиди теперь разрешай конфликты между ними
Но нет. Теперь так нельзя. Нельзя писать запрос и получать ответ. Надо получать массивы в три этапа...
Пойду стакан накачу...
Не в сети