Аутентификация, авторизация и RBAC в Yii2
Много времени прошло с публикации прошлой статьи про структуру ролей и разрешений. В этот раз порассуждали о понятиях и реализациях различных подходов к авторизации, аутентификации и контроле доступа на основе ролей в Yii2. Рассмотрели нюансы, сравнили друг с другом различные подходы к реализации RBAC:
Структура вебинара (кликабельно):
И приглашаю на следующие видеоуроки:
И задавайте вопросы в комментариях. Заранее спасибо и до встречи в эфире!

ПавелУра, наконец-то случилось, как долго я его ждал. Большое спасибо Дмитрий!
SergeyЯ тоже долго ждал именно этот урок! Круто!
Михаил – daxel.ruСпасибо за видеоматериал Дмитрий!
АртемОгромное спасибо за Ваш дело
Евгений Левачевкрасавчик, жаль что так редко выходят уроки
Алексей СундуковА в чем диаграмма нарисована?
Дмитрий ЕлисеевВ XMind.
Александр ХуторненкоУ Вас тут так подробно прописана система авторизации, может подскажете как сделать централизованную авторизацию для двух сайтов к примеру site.com и mail.site.com. site.com - сделан на yii2
Дмитрий ЕлисеевМожно сделать, например, общие cookies, указав site.com в качестве cookie domain.
Александр Хуторненкоа данные, к примеру, общую аватарку для обеих сайтов, общие персональные данные для юзером можно будет таким вариантом реализовать?
Дмитрий ЕлисеевДа, если делать на yii2-app-advanced.
ОлегДмитрий, когда можно будет почитать статейку с доработкой SEO service on Yii2 Framework?
С RABC вполне разобрался, ничего сложного, но Ваш блог очень интересен, многому научился именно от Вас.
xfg$autoRenewCookie это помоему не для того, чтобы куки было сложнее взломать. А чтобы при каждом запросе продлевать время жизни куки. То есть если время жизни куки установлено на 7 дней и $autoRenewCookie = false, то через 7 дней мы гарантировано будем разлогинены. А если true, то если в течении 7 дней были заходы на сайт, то аутентификация не слетит, так как мы своими заходами продлили этой куке жизнь.
Дмитрий ЕлисеевДля осложнения взлома служит authKey.
Альберт ХасановДмитрий подскажите тему следующего вебинара.
Никита – obyava.uaДмитрий, может Вы подскажите хорошие уроки по yii. Хочу начать сначала, а потом уже перейти на yii2
Дмитрий ЕлисеевОфициальное руководство и рецепты на yiiframework.ru, видеоканал Meteor Yii, Богдана Березанского и подобные с курсами на YouTube, мои статьи, loco.ru и прочие блоги.
Дмитрий ЕлисеевК вопросу о том, как форсированно разлогинивать пользователя на всех устройствах при смене его пароля администратором.
Включаем хранение сессий в базе, в таблицу сессий добавляем поле user_id и, собственно, туда вписываем:
'session' => [ 'class' => 'yii\web\DbSession', 'writeCallback' => function () { return ['user_id' => Yii::app()->user->id], }, ],А в контроллере при смене пароля администратором чистим все сессии нужного пользователя:
$db->createCommand() ->delete(Yii::$app->session->sessionTable, ['user_id' => $id]) ->execute();и меняем authKey для инвалидации Cookies.
Родилось случайно здесь.
АлексейДмитрий, а зачем хранить сессии в БД и отягощать систему доп. запросами?
Можно просто добавить поле для юзера (к примеру "force_logout") и при той же операции проставлять ему "true". Всё равно данные пользователя достаются регулярно. Будет на одно поле больше, зато на несколько запросов в базу меньше.
Дмитрий ЕлисеевА когда потом это поле вернуть в false?
АлексейafterLogout().
не искал, что там с getId() юзера при этом, но это уже дело техники (пробросить).
Что скажете? )
Дмитрий ЕлисеевА как это разлогинит все ваши сессии на всех компьютерах и смартфонах?
Алексейнадо помозгововать)
Попов ВасяА примеры с вебинара можете дать?
ДмитрийВ видео Вы коснулись темы логина под другим пользователем. Подскажите, а если я выполнил логин под другим пользователем, этого пользователя выбьет из приложения? И существует ли в Yii2 защита от двойного логина? Буду весьма благодарен, если Вы осветите этот материал.
Спасибо
Дмитрий ЕлисеевВыбъет, так как переменная _identity всего одна, как и cookie с сессией.
Павел МеркуловДмитрий, спасибо большое за познавательный урок!
Вопрос не по теме) Скажите пожалуйста какая тема стоит у вас в хроме, понравился стиль.
Дмитрий ЕлисеевСтандартная тема Ubuntu.
Павел МеркуловСпасибо!
Дмитрий столкнулся с проблемой при аутентификации по HttpBasicAuth
Это написал в котроллере:
public function behaviors() { return [ 'authenticator' => [ 'class' => HttpBasicAuth::className(), 'realm' => 'Enter login and pass!', 'auth' => function($login, $password) { // для примера return null; } ], ]; }Но стандартного окошка авторизации не выводится, вместо этого ошибка:
Дмитрий, скажите пожалуйста что я не так делаю?
Дмитрий ЕлисеевПосмотрите Request в debug-панели. Может уже данные передаются. И попробуйте в другом браузере.
Павел МеркуловВ другом браузере так же. Наверно я не понял как отправлять логин и пароль на нужный адрес, в виде заголовков?
Павел МеркуловВсе, разобрался ) Через curl отправил.
VitalijСкажите пожалуйста, в этом видео есть пример как организовать работу через rest сервис?
Дмитрий ЕлисеевЕсли обращаться к чужому сервису, то использовать любой HTTP-клиент вроде Guzzle. А если из своего сайта делать сервис, то да, подключить любой из тех трёх методов аутентификации.
VitalijСпасибо. Да, из своего сайта делаю сервис. Мобильные приложения должны будут по токену проходить аутентификацию.
SergalasНе подскажите от чего может возникнуть ошибка: Rule not found: group ?
Дмитрий ЕлисеевИз-за того, что не туда вписали или не туда сохранили.
Sergalasвы уже смотрели мой вопрос на yiiframework.ru вопрос в том что и куда я мог не то сохранить ?
Дмитрий ЕлисеевСмотрел.
SergalasСпасибо большое мне уже дали ответ там с неймспейсами проблема была :)
Виталий ЕропкинДмитрий, посмотрел Ваши видео по RBAC, очень понравилось. На основе увиденного и изученного стал делать для работы Админку, ну и заодно изучить Yii2 с этой стороны.
Всё шло хорошо, пока не столкнулся с маааленькой проблемой, которую самостоятельно могу решить, но с "костылями. Проблема следующая:"
1.Yii2, DbManager, PostgreSQL.
2.В миграции сделал так
$auth = Yii::$app->authManager; // добавляем разрешение "fullAccess" $fullAccess = $auth->createPermission('fullAccess'); $fullAccess->description = 'Полный доступ к ресурсам'; $auth->add($fullAccess); // добавляем роль "superadmin" и даём роли разрешение "fullAccess" $superadmin = $auth->createRole('admin'); $superadmin->description = 'Администратор'; $superadmin->data = 'Администратор всего содержимого данной программы, с неограниченным доступом'; $auth->add($superadmin); $auth->addChild($superadmin, $fullAccess); // Назначение роли пользователю superadmin $auth->assign($superadmin, 1);3. Сразу заметил, что
записывается в БД как сериализованная строка
4. При выводе на экран, вот это s:142: не исчезает. Вывожу обычным DetailView::widget()
5. Сделал так:
[ 'label' => 'Подробное описание', 'value' => unserialize($model->data), ],не помогло.
6. С
та же проблема.
7. Нашёл костыль и записал в верху контроллера эту строку
iconv_set_encoding('input_encoding', 'UTF-8');Помогло, unserialize заработал, но это костыль((( Можно как-то лучше сделать? Ошибка похоже банальная и где-то на поверхности , но не могу понять какая.
Основной вопрос по RBAC:
1. Как лучше апдейтить RBAC данные в БД?
2. По стандарту вот так
$model = $this->findModel($id); // $model модель AuthItem (по таблице Auth_Item) созданная RBAC if ($model = load(Yii::$app->request->post()) && $model->save()) { .....}Поле "data" не сериализуется, мне её самому сериализовать? или есть методы поближе к
authmanager() ?
Дмитрий ЕлисеевC использованием поля data для хранения описания не втречался. Обычно хватает description. А насчёт сериализации - увы, в Yii нет настраиваемого преобразования значений из базы и обратно, так что чаще всего все костылят это в методах afterFind (или instantiate) и beforeSave.
Виталий Еропкинт.е. если я напишу методы afterFind и beforeSave в модели AuthItem, то они будут работать послеПоиска и ПередСохранением?
Дмитрий ЕлисеевДа.
Виталий ЕропкинПросто сделать beforeSave() не разрешил Yii2))) Говорит есть у меня такой метод, поэтому сделай как я хочу)) Сделал по "его"
public function beforeSave($insert) { if (parent::beforeSave($insert)) { $this->data = serialize($this->data); return true; } else { return false; } }
Виталий ЕропкинПодскажите, чтобы такой фильтр написать https://yadi.sk/d/ZSH3Uf-Mnixun , только Yii2 методов хватит? или по-любому JS писать надо? Хочу научиться писать фильтры используя Yii2. Вот тут образец взял
http://rubkoff.ru/proekty/doma/iz-sruba?price1=on&area2=on&floor2=on&type3=on&view3=on
Сложный, но зато всё можно научиться для фильтров писать.
Дмитрий ЕлисеевПростые hidden-поля для формы и небольшой JS.
Андрей ЕськовДмитрий подскажите, к примеру, группе пользователей дано право удаление только своих контактов, как сделать проверку на уровне AccessControl
Вот так проверка работает отлично (во вьюхах и экшенах)
[ 'class' => 'yii\grid\ActionColumn', 'template' => '{update}{delete}', 'buttons' => [ 'update' => function ($url , $model) { return Yii::$app->user->can('update_Contact' , ['contact' => $model]) ? Html::a('<span class="btn btn-xs btn-white btn-info"><i class="fa fa-pencil"></i></span>', $url) : ''; }, 'delete' => function ($url , $model) { return Yii::$app->user->can('delete_Contact' , ['contact' => $model]) ? Html::a('<span class="btn btn-xs btn-white btn-danger"><i class="fa fa-trash"></i></span>', $url , [ 'data' => [ 'confirm' => 'Уверен что хочешь удалить контакт?', 'method' => 'post', ] ]): ''; }, ], 'headerOptions' => ['width' => '80px'], ],Или просто открыть доступ до экшена удаления в AccessControl и в самом экшене уже проверять есть доступ, то велком нет доступа то форбитн.
Дмитрий ЕлисеевДа. чаще всего именно в экшенах и делают:
public function actionUpdate($id) { $model = $this->findModel($id); if (!Yii::$app->user->can('update_Contact' , ['contact' => $model])) { throw new ForbiddeHttpException(); } ... }
Виталий ЕропкинДмитрий. Вопрос опять по RBAC.
Не получается сделать по простому изменение полномочий пользователя. Сделал как-то грубо и много. Посмотрите на код, пожалуйста, это опять костыли? По проще ни как нельзя?
public function actionUpdate($id) { $model = $this->findModel($id); if ($model->load(Yii::$app->request->post()) && $model->save()) { $newrole = Yii::$app->request->post('Users')['roles']; $auth = Yii::$app->authManager; $oldrole = array_keys($auth->getRolesByUser($model->id_user))[0]; $newrole = $auth->getRole($newrole); $oldrole = $auth->getRole($oldrole); $auth->revoke($oldrole, $model->id_user); $auth->assign($newrole , $model->id_user); return $this->redirect(['view', 'id' => $model->id_user]); } else { $model->roles = Yii::$app->authManager->getRoles(); $role = Yii::$app->authManager->getRolesByUser($id); return $this->render('update', [ 'model' => $model, 'role' => $role, ]); } }
Виталий ЕропкинЯ тут хочу - Изменить "группу" (роль) у пользователя. У меня сделано так, что пользователь-(работник) входит в одну Группу в которой есть свои полномочия(разрешения). И как-то странно, что нет Update для assign().
Дмитрий ЕлисеевУдалить старую можно через revokeAll:
Виталий ЕропкинСпасибо. Сегодня испытаю. Не думал, что All можно для одного))
Виталий Еропкинтолько тут небольшая поправка.
$newrole должно быть объектом класса Role, поэтому исправил
и всё работает.
Спасибо.
ЮрийДобрый день!!
Возможно глупый вопрос но все же..
как разделить админов от пользователей в разные таблицы?
и как настроить страницу авторизации для пользователей и админов разные?
Дмитрий ЕлисеевА зачем их по таблицам разделять?
А так в app-advanced можно указать разные loginUrl и разные модели identityClass для компонента user.
ЮрийСпасибо..
я так и понял..
да я это подсмотрел в opencart..
АндрейСкажите пожалуйста, каким способом можно ограничить доступ к методам стороннего модуля? Например yii2-admin
Дмитрий ЕлисеевМожно навесить поведение прямо к классу модуля:
'modules' => [ 'admin' => [ 'class' => '...', 'as access' => [ 'class' => 'yii\filters\AccessControl', 'rules' => [ ... ], ], ], ],
АндрейБлагодарю!
Если вас не затруднит, можно более подробно раскрыть данный вопрос?
Например я использую RBAC, в backend (админку) у меня имеют доступ 2 роли (roles): модератор и администратор и есть permission: enterSetupRbac, которая на данный момент есть только у администратора. Я хочу открыть функционал модуля yii-admin только для тех, у кого есть permission enterSetupRbac.
И в целом хотелось бы понять как можно гибко настраивать доступ к actions модулей на основе permissions.
Прошу прощения, если мои вопросы покажутся вам глупыми, я только начинаю изучать yii-2, до этого приходилось иметь дело только с kohana и CI.
Дмитрий ЕлисеевЕсли закрыть весь модуль, то:
'rules' => [ [ 'allow' => true, 'roles' => ['enterSetupRbac'], ], ],Если конкретные контроллеры, то перечислить в actions:
'rules' => [ [ 'controllers' => ['users'], 'allow' => true, 'roles' => ['usersView'], ], ],
АндрейОгромное спасибо!
Оказывается все просто.
girmateА если мне нужно в весь /backend ограничить доступ для всех кроме admin?
Дмитрий ЕлисеевВ backend/config/main.php:
'as access' => [ 'class' => 'yii\filters\AccessControl', 'except' => ['site/login', 'site/error'], 'rules' => [ [ 'allow' => true, 'roles' => ['admin'], ], ], ],
ФилипРоль гостя возможно создать через $authManager->createPermission('guest') и далее через Yii::$app->user->can() проверять доступ? Я так понимаю для гостей в Yii:$app->user->identity необходимо что-то хранить?
Дмитрий ЕлисеевМожно сделать createRole('guest') и прописать defaultRoles => ['guest']. А в Yii:$app->user->identity попадает только модель залогиненного пользователя.
ФилипБлагодарю, т.е. все кто не залоген будут иметь роль guest. Всех благ Вам и Вашему труду!
ДжониЯ не понят, от куда берется $post = new Post([///]) ?
Mat4 часа... Гигант !!!
АлексейПодскажите, если у нас есть две роли user и admin и в defaultRoles мы укажем user, то в файле assignmenst все равно каждый пользователь будет привязываться к роли user?
Дмитрий ЕлисеевРоли из defaultRoles привязываются ко всем посетителям. На то они и роли по умолчанию.
АлексейПросто я подумал, что раз уж есть слово "по умолчанию" то ничего привязывать не надо, т.е. все пользователи автоматически становятся User без записи в файл. Тогда бы было удобно даже при миллионе пользователей использовать phpmanager, где в файле привязки мы бы привязывали только администраторов и модераторов, а все остальные бы считались автоматически User.
ПавелСпасибо за видеоматериал. Все доступно объяснили. А есть ли возможность в yii2 авторизоваться используя pam аутентификацию. В Astra Linux она обязательна((
Дмитрий ЕлисеевНайти PHP-код для такой аутентификации и реализовать по аналогии с BasicAuth или BearerAuth.
Tima BogomolovДмитрий, добрый день. Проверка ролей и разрешений идет в обратную сторону, рекурсивно проверяя всех родителей и все их правила пока не доберется до основной роли. Как исключить проверку "неакутальных" правил для роли. Скажем если фильтр
[ 'allow' => true, 'actions' => ['update'], 'roles' => ['updatePost'], ],а в конфиге "aupdateOwnPost - updatePost" (aupdateOwnPost нарочно начинается с символа "a")
то в таком случае в checkAccess если пользователь с ролью админ, то будет проверятся по цепочке
updatePost - aupdateOwnPost - author, и только затем updatePost - admin
Как исключить проверку aupdateOwnPost ?
Как правильно организовать цепочку ролей/разрешений с правилами если их несколько, чтобы для пользователей admin и author применялись свои правила, пусть они и пересекаются?
Дмитрий ЕлисеевОбычно проверка производится для одного объекта, а не для сотен или тысяч в цикле, так что это будет экономия на спичках. Так что нет смысла оптимизировать.
Навчання – www.ndo.com.uaСпасибо большое за информацию! Хоть прошло уже не мало времени, но она всё ещё помогает)
LissaShteinДействительно. Кстати можно ещё тут курсы глянуть: https://www.ndo.com.ua/ru/services/education-training-courses.html