Yii2da avtorizatsiya va rollar

Yii2da avtorizatsiya va rollar

Avtorizatsiya

Avtorizatsiya – bu tizimga kirgan foydalanuvchida belgilangan faoliyatni amalga oshirishga huquqi bor yoki yo'qligini tekshirish.Yii freymvorkida avtorizatsiyani amalga oshirish uchun ikki xil usul mavjud: ruxsatni filterlab boshqarish(ACF – Access Control Filter) va rolga asoslangan boshqarish(RBAC – Role Based Access Control).

Ruxsatni filterlab boshqarish(ACF)

Ba'zi tizimlar oddiy tuzilishga ega bo'lgani sababli ularga ruxsatni boshqarishning oddiy usullarini qo'llash samaraliroq hisoblanadi. Ruxsatni filterlab boshqarish shunday usullardan biri hisoblanadi. Nomidan ko'rinib turibdiki, ACF – kontrollerga yoki modulga xuddi behavior(“harakat") sifatida qo'shiladi. ACF foydalanuvchida belgilangan harakat uchun ruxsat borligiga ishonch hosil qilish uchun “ruxsat qoidalarini" tekshirib chiqadi.

Quyidagi kod yii\filters\AccessControl bilan yaratilgan ACFdan qanday foydalanish kerakligini ko'rsatadi:

use yii\web\Controller;
use yii\filters\AccessControl;
class SiteController extends Controller
{
    public function behaviors()
    {
        return [
            'access' => [
                'class' => AccessControl::className(),
                'only' => ['login', 'logout', 'signup'],
                'rules' => [
                    [
                        'allow' => true,
                        'actions' => ['login', 'signup'],
                        'roles' => ['?'],
                    ],
                    [
                        'allow' => true,
                        'actions' => ['logout'],
                        'roles' => ['@'],
                    ],
                ],
            ],
        ];
    }
    // ...
}

Yuqoridagi kodda ACF kontrollerga behaviors() funksiyasi orqali bog'langan. Bu tizimda faoliyatni filterlashning odatiy usullaridan biri hisoblanadi. Bu yerda only parametri ACF faqat login, logout, signup metodlari uchun ishlashi kerakligini ko'rsatyapti. rules parametri esa quyidagi ma'noni bildiruvchi ruxsat qoidalarini o'rnatadi:

  • Barcha tizimdan ro'yxatdan o'tmagan foydalanuchi(mehmon)larga login va signup metodlarini ishlatishga ruxsat berish. Bunda roles parametri ? belgisini oladi(? – tizimga kirmagan foydalanuvchini bildiradi).
  • Tizimga kirgan foydalanuvchiga logout metodidan foydalanishga ruxsat beradi. Tizimga kirgan foydalanuvchi @ belgisi bilan ifodalanadi.

ACF avtorizatsiya tekshiruvini boshlagan paytda ruxsatlarni yuqoridan pastga qarab bittalab moslikni topmagunicha amalga oshiradi. Tanlangan qoidaning allow parametri foydalanuvchiga ruxsat berish kerakmi yoki yo'qligini belgilaydi. Agar berilgan birorta qoida foydalanuvchiga mos kelmasa foydalanuvchi berilgan metod uchun avtorizatsiyalanmagan hisoblanadi va ACF keying qoidani tekshirishga o'tadi.

Odatda agar foydalanuvchida berilgan metodaga ruxsat bo'lmasa, ACF quyidagilarni bajaradi:

  • Agar foydalanuvchi mehmon bo'lsa foydalanuvchini tizimga kirish sahifasiga o'tkazuvchi yii\web\User::loginRequired() ni chaqiradi.
  • Agar foydalanuvchi tizimga kirgan bo'lsa istisno matnini shakllantiruvchi yii\web\ForbiddenHttpException classni chaqiradi(bunda 403 xabar bilan “sahifaga ruxsat yo'q" mazmunidagi xabar chiqariladi).

Bu behaviorni yii\filters\AccessControl::denyCallback xususiyatini sozlab qaytadan o'zingizga moslab yozishingiz mumkin:

[
    'class' => AccessControl::className(),
    ...
    'denyCallback' => function ($rule, $action) {
        throw new \Exception('You are not allowed to access this page');
    }
]

Ruxsat qoidalarida ba'zi parametrlar to'plami mavjud. Quyida shu parametrlarning qisqa ta'rifi keltirilgan. Shu bilan birga yii\filters\AccessRule classdan meros olib o'zingizning shaxsiy ruxsat qoidalari klassingizni yaratishingiz mumkin:

  • allow – ruxsat turini belgilaydi: “allow" va “deny".
  • actions – berilayotgan qoidalar qaysi metodlarga qo'llanilishini belgilaydi. Bu parameter qiymati massiv ko'rinishida bo'ladi. Agar massiv bo'sh qoldirilsa qoida barcha metodlar uchun qo'llaniladi.
  • controllers – qoidalar amal qilishi kerak bo'lgan kontrollerlar idsi. Qiymati massiv bo'lishi kerak. Agar massiv bo'sh qoldirilsa qoida barcha kontrollerlar uchun amal qiladi.
  • roles – berilayotgan qoida qaysi rollarga amal qilishini belgilaydi. Odatda ikki turdagi rol yii\web\User::isGuest yordamida tekshiriladi:
    • ? – tizimga kirmagan foydalanuvchi;
    • @ - tizimga kirgan foydalanuvchi;

RBAC(keyinroq tanishamiz) yordamida yaratilgan qolgan rollar yii\web\User::can() funksiyasi yordamida tekshiriladi. Agar ushbu parameter bo'sh qoldirilsa demak qoida barcha foydalanuvchilar uchun amal qiladi.

  • ips – berilgan qoidalar qaysi ipdagi foydalanuvchi uchun amal qilish kerakligini belgilaydi. IP manzil oxirida * belgisi ham bo'lishi mumkin. Bu degani qoida berilgan IP manzilning boshlang'ich manzillariga mos kelgan barcha IP manzillar uchun amal qiladi. M: '192.168.*' degani 192.168 bilan boshlanuvchi barcha IP manzillar berilgan qoidaga bo'ysunadi degani. Agar parameter bo'sh qoldirilsa qoida barcha IPlar uchun amal qiladi.
  • verbs – belgilangan qoidaga http metod(GET, POST) beradi.
  • matchCallback – berilgan qoida nima amal bajarishi kerakligini ko'rsatuvchi php callback funksiya.
  • denyCallback – berilgan qoida foydalanuvchini amal bajarishni taqiqlagan paytda qanday vazifa bajarishini belgilaydi.

Quyida matchCallbackni ishlatishga misol keltirilgan. Bunda ixtiyoriy ruxsatni tekshirish imkonini beradi.

use yii\filters\AccessControl;
class SiteController extends Controller
{
    public function behaviors()
    {
        return [
            'access' => [
                'class' => AccessControl::className(),
                'only' => ['special-callback'],
                'rules' => [
                    [
                        'actions' => ['special-callback'],
                        'allow' => true,
                        'matchCallback' => function ($rule, $action) {
                            return date('d-m') === '31-10';
                        }
                    ],
                ],
            ],
        ];
    }
    // Match callback called! This page can be accessed only each October 31st
    public function actionSpecialCallback()
    {
        return $this->render('happy-halloween');
    }
}

Ruxsatlarni rollar asosida boshqarish (RBAC)

https://yiiframework.com.ua/ru/doc/guide/2/security-authorization/

Rollarga asoslangan boshqaruv oddiy lekin juda kuchli ruxsatlarni boshqarish usuli hisoblanadi. Uning boshqa ruxsatlarni boshqarish usullaridan farqini internet orqali ko'rib olishingiz mumkin.

Yii NIST RBACka asoslangan iyerarxik RABCdan foydalanadi. RBAC authManager komponenti orqali ishga tushiriladi va foydalaniladi.

RBACdan foydalanish ikki bosqichda amalga oshiriladi. Birinchi bosqichda RBAC ma'lumotlari – ruxsatlar, rollar, ruxsat va rollar iyerarxiyasi kabilar shakllantiriladi. Ikkinchi bosqichda yaratib olingan ma'lumotlar yordamida kerakli joyda kerakli faoliyat uchun ruxsat berishlar amalga oshiriladi. Tushunish osonroq bo'lishi uchun ba'zi RBAC haqidagi asosiy ma'lumotlarni beramiz.

Asosiy tushunchalar.

Rol bir qancha ruxsatlar(permissions)(masalan yozishga ruxsat, o'zgartirishga ruxsat) to'plamidan iborat bo'ladi. Rol bitta yoki ko'p foydalanuvchilarga berilishi mumkin. Foydalanuvchida belgilangan faoliyatni amalga oshirishga ruxsat bor yoki yo'qligi undagi ruxsatlardan tashkil topgan rol bor yo'qligini tekshirish orqali aniqlanadi.

Har bir rol yoki ruxsatga biror bir qoida(rule) biriktirilgan bo'lishi mumkin. Bu qoida foydalanuvchida ruxsat bor yoki yo'qligini tekshirishda ishga tushadi. Masalan, “maqolani o'zgartirish" ruxsatiga shu ruxsatdan foydalanayotgan foydalanuvchi berilgan maqolaning egasiligini tekshiruvchi qoida bog'langan bo'lishi mumkin. Ruxsatni tekshirish paytida shu ruxsatga bog'langan qoida foydalanuvchini maqola egasi deb topmasa unga maqolani o'zgartirishga ruxsat bermaydi.

Rollar ham, ruxsatlar ham iyerarxiya bilan o'zaro birlashtirilishi mumkin. Kerakli holatlarda rolga boshqa roller va ruxsatlar, ruxsatlarga boshqa ruxsatlar bog'lanishi mumkin. Yii o'z ichiga daraxtli iyerarxiyani oladigan qisman tartiblangan iyerarxiyadan foydalanadi.

RBAC managerni sozlash.

Ruxsat va rollarni yaratishdan oldin authManager komponentini ilovada sozlash kerak bo'ladi. Yii ikki turdagi avtorizatsiyalash menejerlariga ega: yii\rbac\PhpManage va yii\rbac\DbManager. 1-menejer ruxsat va rollarni php faylda saqlaydi, 2-si esa bazada. Agar sizning saytingizda o'zgarmas sondagi ruxsat va rollar bo'ladigan bo'lsa, birinchisidan foydalanganingiz ma'qulroq.

AuthManagerni PhpManager orqali sozlash.

Quyidagi kod orqali PhpManager komponentasini ilovada ishga tushirishingiz mumkin. Bu kod congfig/main.php faylida (advanced turda frontend\config\main.php yoki common\config\main.php yoki backend\config\main.php – qayerda foydalanishingizga qarab) yoziladi:

return [
    // ...
    'components' => [
        'authManager' => [
            'class' => 'yii\rbac\PhpManager',
        ],
        // ...
    ],
];

AuthManager sozlangandan keyin uni Yii::$app->authManager orqali ishlatish mumkin.

!. Odatda yii\rbac\PhpManager o'z ma'lumotlarini @app/rbac/ papkasidagi fayllarda saqlaydi. Agar bunday papka va fayllar bo'lmasa ularni yaratib serverga ulardan foydalanish ruxsatini yoqish kerak bo'ladi.

AuthManagerni DbManager orqali sozlash.

Quyidagi kod orqali DbManager komponenti sozlanadi. Bu sozlash PhpManagerniki bilan bir xil.

  return [
    // ...
    'components' => [
        'authManager' => [
            'class' => 'yii\rbac\DbManager',
            // uncomment if you want to cache RBAC items hierarchy
            // 'cache' => 'cache',
        ],
        // ...
    ],
];

Yuqorida aytilganidek DbManager o'z ma'lumotlarini ma'lumotlar bazasida saqlaydi. Bunda u 4ta jadvaldan foydalanadi.

  • itemTable: autorizatsiyalash elementlari saqlanadi. Odatdagi nomi – auth_item.
  • itemChildTable: elementlar iyerarxiyasini saqlash jadvali. Odatdagi nomi – auth_item_child.
  • assignmentTable: avtorizatsiyalash elementlarini foydalanuvchilarga biriktirish jadvali. Odatdagi nomi – auth_assignment.
  • ruleTable: qoidalar jadvali. Odatdagi nomi – auth_rule.

DbManagerni sozlagandan keyin yuqoridagi to'rtta jadvalni yaratib olish kerak bo'ladi. Buning uchun Yiida @yii/rbac/migrations papkasida tayyor migratsiya fayllari bor:

yii migrate --migrationPath=@yii/rbac/migrations

Shundan so'ng authManagerni Yii::$app->authManager orqali ishlatish mumkin.

Avtorizatsiyalash ma'lumotlarini yaratish.

Avtorizatsiyalash ma'lumotlarini yaratish uchun quyidagi vazifalarni bajarish kerak:

  • rol va ruxsatlarni yaratish;
  • rol va ruxsatlarni o'zaro bog'lash;
  • qoidalarni yaratish;
  • qoidalarni ruxsat va rollar bilan bog'lash;
  • rollarni foydalanuvchilarga berish;

Avtorizatsiya mustahkamligiga bo'lgan talabga qarab yuqorida sanab o'tilgan vazifalar turli xil yo'llar bilan bajarilishi mumkin.

Agar qoidalar iyerarxiyasi o'zgarmas bo'lsa va foydalanuvchilar soni doimiy bo'lsa authManagerda mavjud bir martalik initsializatsiyalash konsol buyrug'idan foydalangan ma'qul:

<?php namespace app\commands;
use Yii;
use yii\console\Controller;
class RbacController extends Controller
{
    public function actionInit()
    {
        $auth = Yii::$app->authManager;
        $auth->removeAll();
        // add "createPost" permission
        $createPost = $auth->createPermission('createPost');
        $createPost->description = 'Create a post';
        $auth->add($createPost);
        // add "updatePost" permission
        $updatePost = $auth->createPermission('updatePost');
        $updatePost->description = 'Update post';
        $auth->add($updatePost);
        // add "author" role and give this role the "createPost" permission
        $author = $auth->createRole('author');
        $auth->add($author);
        $auth->addChild($author, $createPost);
        // add "admin" role and give this role the "updatePost" permission
        // as well as the permissions of the "author" role
        $admin = $auth->createRole('admin');
        $auth->add($admin);
        $auth->addChild($admin, $updatePost);
        $auth->addChild($admin, $author);
        // Assign roles to users. 1 and 2 are IDs returned by IdentityInterface::getId()
        // usually implemented in your User model.
        $auth->assign($author, 2);
        $auth->assign($admin, 1);
    }
}

Advanced turida RbacController console/controllers papkasida joylashadi hamda uning nomlar fazosi(namespace) console/controllers ga o'zgartiriladi.

Shundan so'ng konsolda yii rbac/init buyrug'I ishlatiladi. U quyidagi iyerarxiyani yaratadi:

Bu iyerarxiyaga qaraydigan bo'lsak, muallif post yaratishi mumkin. Administrator esa postni o'zgartirishi va muallif bajaradigan barcha ishlarni qila oladi.

Ayrim saytlarda yangi foydalanuvchi ro'yxatdan o'tish imkoniyati bo'ladi. Bunda yangi ro'yxatdan o'tgan foydalanuvchiga boshlang'ich rol berib qo'yish kerak bo'ladi. Masalan, yangi ro'yxatdan o'tgan foydalanuvchi saytga kirganda avtomatik muallif rolini berish kerak bo'lsin. Bunda frontend\models\SignupForm::signup() da quyidagi o'zgarishlarni qilish kerak bo'ladi:

 public function signup()
{
    if ($this->validate()) {
        $user = new User();
        $user->username = $this->username;
        $user->email = $this->email;
        $user->setPassword($this->password);
        $user->generateAuthKey();
        $user->save(false);
        // the following three lines were added:
        $auth = \Yii::$app->authManager;
        $authorRole = $auth->getRole('author');
        $auth->assign($authorRole, $user->getId());
        return $user;
    }
    return null;
}

Avtorizatsiya ma'lumotlari dinamik o'zgarib turadigan murakkab ko'rinishdagi ruxsatlarni boshqarishda authManager tomonidan taqdim qilinadigan API yordamida ishlab chiqilgan maxsus foydalanuvchi interfeyslari(admin-panel deb nomlanadi) mavjud.

Qoidalardan foydalananish.

Yuqorida aytilganidek, qoidalar rol va ruxsatlarga qo'shimcha cheklanish beradi. Qoidalar yii\rbac\Rule klasidan meros olib yaratilgan klasslardir. Ular execute() funksiyasi orqali ishga tushiriladi. Yuqorida biz yaratgan iyerarxiya bo'yicha muallif o'zining postini yangilay olmaydi. Endi shuni o'zgartirib ko'raylik. Muallif o'z postini o'zgartira olsin. Buning uchun avvalo, avtorni berilgan postning egasiligini tekshiruvchi qoida yaratamiz:

namespace app\rbac;
use yii\rbac\Rule;
use app\models\Post;
/**
 * Checks if authorID matches user passed via params
 */ class AuthorRule extends Rule
{
    public $name = 'isAuthor';
    /**
     * @param string|int $user the user ID.
     * @param Item $item the role or permission that this rule is associated with
     * @param array $params parameters passed to ManagerInterface::checkAccess().
     * @return bool a value indicating whether the rule permits the role or permission it is associated with.
     */
    public function execute($user, $item, $params)
    {
        return isset($params['post']) ? $params['post']->createdBy == $user : false;
    }
}

Yuqoridagi qoida post $user tomonidan yaratilganligini tekshiradi. updateOwnPost degan maxsus ruxsatni RbacControllerga qo'shib yaratib olamiz:

$auth = Yii::$app->authManager;
// add the rule $rule = new \app\rbac\AuthorRule;
$auth->add($rule);
// add the "updateOwnPost" permission and associate the rule with it. $updateOwnPost = $auth->createPermission('updateOwnPost');
$updateOwnPost->description = 'Update own post';
$updateOwnPost->ruleName = $rule->name;
$auth->add($updateOwnPost);
// "updateOwnPost" will be used from "updatePost" $auth->addChild($updateOwnPost, $updatePost);
// allow "author" to update their own posts $auth->addChild($author, $updateOwnPost);

Natijada quyidagi iyerarxiyaga ega bo'lamiz:

Ruxsatni tekshirish.

Avtorizatsiyalash ma'lumotlarini tekshirish amali bu shunchaki yii\rbac\ManagerInterface::checkAccess() klassini chaqirish hisoblanadi. Ko'pchilik tekshirishlar joriy foydalanuvchi uchun amalga oshirilgani sababli Yiida yii\web\User::can() qisqa metodi mavjud:

if (\Yii::$app->user->can('createPost')) {
    // create post
}

Agar IDsi 1 ga teng bo'lgan joriy foydalanuvchini Jeyn deb olsak, createPost ruxsatini Jeyn qanday ishlatishini ko'ramiz:

Joriy foydalanuvchi postni o'zgartira olishini tekshirish uchun AuthorRule ga kerak bo'ladigan qo'shimcha parametrdan foydalanish kerak bo'ladi:

if (\Yii::$app->user->can('updatePost', ['post' => $post])) {
    // update post
}

Agar joriy foydalanuvchi Jon bo'lsa quyidagi holat yuz beradi:

Bunda updatePost ruxsatidan boshlab updateOwnPost ruxsatiga o'tamiz. Bu o'tish yuz berishi uchun esa AuthorRule klassining execute metodi true qaytarishi kerak. Metod can metodida berilgan va ['post' => $post] ga teng bo'lgan $params ni oladi. Agar hammasi to'g'ri qilingan bo'lsa author Jonga bog'langanligini ko'ramiz.

Jeyn holatida bu ancha soddaroq. Chunki u admin:

Kontrollerda avtorizatsiyalash(ya'ni ruxsatlarni tekshirish)ning bir qancha usullari mavjud. Agar sizga o'chirish va qo'shishga alohida qoida kerak bo'lsa, u holda siz tekshirishni har bir harakat(action)da amalga oshirasiz. Buning uchun yuqoridagi shartni har bir harakat ichida amalga oshirasiz yoki yii\filters\AccessControl dan foydalanasiz:

public function behaviors()
{
    return [
        'access' => [
            'class' => AccessControl::className(),
            'rules' => [
                [
                    'allow' => true,
                    'actions' => ['index'],
                    'roles' => ['managePost'],
                ],
                [
                    'allow' => true,
                    'actions' => ['view'],
                    'roles' => ['viewPost'],
                ],
                [
                    'allow' => true,
                    'actions' => ['create'],
                    'roles' => ['createPost'],
                ],
                [
                    'allow' => true,
                    'actions' => ['update'],
                    'roles' => ['updatePost'],
                ],
                [
                    'allow' => true,
                    'actions' => ['delete'],
                    'roles' => ['deletePost'],
                ],
            ],
        ],
    ];
}

Agar qoida CRUDning barcha amallari uchun birgalikda berilsa, bu holatdagi eng yaxshi yechim managePost kabi bitta ruxsat yaratish kerak va uni yii\web\Controller::beforeAction() ichida tekshirish kerak.

Odatiy holda rollardan foydalanish.

Rol odatiy holda barcha foydalanuvchilarga bilvosita(to'g'ridan-to'g'ri emas) beriladi. Bunda yii\rbac\ManagerInterface::assign() metodini ishlatish talab qilinmaydi hamda avtorizatsiyalash ma'lumotlarida rol berish haqida ma'lumot saqlanmaydi.

Odatda rol qoidalar bilan bog'langan bo'ladi va bu qoidalar qaysi rol qaysi foydalanuvchiga tegishliligini aniqlaydi.

Rol rollar tavsifi mavjud bo'lgan ilovalarda foydalaniladi. Masalan, ilovaning foydalanuvchilar jadvalida “group" ustuni bo'lishi mumkin va har bir foydalanuvchi biror guruhga tegishli bo'ladi. Agar har bir guruhga RBAC modelidagi rollar berilgan bo'lsa, u holda bu rolni avtomatik tarzda guruhdagi har bir foydalanuvchiga beriladi. Osonroq tushunish uchun misol ko'raylik.

Faraz qilaylik foydalanuvchilar jadvalida 'group' ustuni mavjud va agar bu ustun qiymati 1 bo'lsa foydalanuvchilari 'admin', 2 bo'lsa 'avtor' bo'ladi. Ikkita guruhga berish uchun admin va muallif rollarini yaratamiz. Rol ma'lumotlarini quyidagi ko'rinishda sozlash mumkin:

namespace app\rbac;
use Yii;
use yii\rbac\Rule;
/**
 * Checks if user group matches
 */ class UserGroupRule extends Rule
{
    public $name = 'userGroup';
    public function execute($user, $item, $params)
    {
        if (!Yii::$app->user->isGuest) {
            $group = Yii::$app->user->identity->group;
            if ($item->name === 'admin') {
                return $group == 1;
            } elseif ($item->name === 'author') {
                return $group == 1 || $group == 2;
            }
        }
        return false;
    }
}

Kodda ko'rib turganizdek, “author" “admin"ga farzand element sifatida qo'shiladi. Shu sababli execute() metodini ishlatishda ushbu iyerarxiyani hisobga olish kerak. Shuning uchun ham foydalanuvchi 1- yoki 2- guruhga tegishli bo'lganda “author" roli uchun execute() metodi rost qiymat qaytaradi(bu foydalanuvchi admin yoki muallif guruhiga tegishliligini bildiradi).

yii\rbac\BaseManager::$defaultRoles xususiyatida sanab o'tilgan rollar yordamida authManager ni sozlab olamiz:

return [
    // ...
    'components' => [
        'authManager' => [
            'class' => 'yii\rbac\PhpManager',
            'defaultRoles' => ['admin', 'author'],
        ],
        // ...
    ],
];

Endi, agar ruxsatni tekshirish amalga oshirilsa, ikkala admin va muallif rollari uchun qoidani ekshirish amalga oshiriladi. Agar qoida rost qiymat qaytarsa demak rol joriy foydalanuvchiga amal qiladi. Yuqorida yaratilgan qoida asosiga ko'ra: agar foydalanuvchi 1-guruhga kirsa demak unga admin roli, agar 2-guruhga kirsa muallif roli qo'llaniladi.

Manba:


AlisherN - Texnoman foydalanuvchisi

Muallif haqida

AlisherN


Blogdagi so‘nggi maqolalar:


Birinchi bo‘ling!

Iltimos, fikr bildirish uchun saytga kiring yoki ro‘yxatdan o‘ting!