احسان رضایی

یک توسعه دهنده

درس های yii2 شماره 16: کنترل سطح دسترسی، Role Based Access یا RBAC

در yii2 , / تاریخ ارسال 02-04-1396 / 1 نظر / آخرین ویرایش 30-08-1403

 مفاهیم پایه

Role Based Access Control یا به طور خلاصه RBAC یک سیستم مدیریت دسترسی هاست که در yii2 گنجانده شده. هر نقش(role) در RBAC شامل مجموعه ای از مجوز هاست یک نقش میتونه به یک یا چند کاربر اختصاص داده بشه. به عنوان مثال نقش manage user(مدیریت کاربران) میتونه شامل مجوز های add user, edit user و delete user باشه. به منظور کنترل سطح دسترسی باید مشخص بشه آیا به کاربر جاری نقش یا مجوز لازم اختصاص داده شده یا خیر.

نقش ها و یا مجوز ها میتونن سازمان یافته و سلسله مراتبی باشن یعنی یک نقش میتونه شامل نقش های دیگه ای باشه، مجوز ها هم همینطور.

به عنوان مثال فرض کنید یک سیستم مدیریت مقالات داریم. کاربران این سیستم شامل سه گروه میشن:

  1. کاربران عادی که میتونن مقالات رو بخونن یا مقاله ارسال کنن.
  2. ناظم هایی که میتونن مقالات ارسال شده توسط گروه اول رو ویرایش، تایید و یا حذف کنن.
  3. مدیرانی که میتونن هر کاری انجام بدن از جمله مدیریت کاربران و...

در این مثال برای گروه اول نیازی نیست سطح دسترسی تعریف کنیم و یا اینکه مجوزی مورد بررسی قرار بگیره! چون تمام کاربران باید بتونن مقالات رو بخونن و یا مقاله ارسال کنن.

برای گروه دوم میشه یک نقش تعریف کرد با عنوان managing articles و برای گروه سوم هم که قراره کاربران رو مدیریت کنن نقش managing users رو داریم. نقش ها و مجوز ها باید به صورت سلسله مراتبی تعریف بشن چون گروه سوم یا مدیران ما علاوه بر مدیریت کاربران باید بتونن مقالات رو هم ویرایش، تایید و یا حذف کنن یعنی نقش های گروه دوم رو هم باید داشته باشن پس طرح سلسله مراتبی ما چیزی مثل تصویر زیر خواهد شد:

rbac

پیاده سازی

قبل از اینکه پیاده سازی رو انجام بدیم باید authManager رو پیکره بندی کنیم. برای پیکره بندی authManager دو روش وجود داره. استفاده از PhpManager و یا DbManager. اگر از روش اول استفاده کنید باید تمام اطلاعات مربوط به سطح دسترسی های کاربرانُ در یک یک فایل php قرار بدین. این روش معمولا برای زمانی هست که نقش ها ثابت هستن و نیازی به مدیریت مجوز ها ندارید.

در روش دوم، اطلاعات مربوط به دسترسی ها داخل پایگاه داده ذخیره میشه. امکان مدیریت پویا به آسانی فراهم شده و همچنین وضوح بیشتری نسبت به روش اول داره. برای استفاده از این روش پیکره بندی زیرُ انجام میدیم(common/config/main.php)

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

حالا برای مقداردهی اولیه rbac از migrations استفاده میکنیم.

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

برای DbManager داخل پایگاه داده 4 جدول ساخته میشه:

  1. auth_item: جدول مربوط به ذخیره سازی مجوز ها(مجوز ها در این جدول نگهداری میشوند).
  2. auth_item_child: مربوط به سلسله مراتب مجوز هاست، مشخص کننده ارتباط پدر و فرزندی مجوز ها.
  3. auth_assignment: مشخص میکند کدام مجوز به کدام کاربر اختصاص داده شده.
  4. auth_rule: جدول نگهداری قوانین.

برای مقدار دهی اولیه و همیچنین تغییر مجوز و نقش ها باز هم از migrations استفاده کنیم.

./yii migrate/create init_rbac

اگر دستور شما با موفقیت اجرا شده باشه باید در قسمت migration هاتون یک فایل با نامی مثل m141204_121823_init_rbac داشته باشید. بازش کنید چون تصمیم داریم قبل از up کردنش نقش ها و مجوز هامون رو داخلش تعریف کنیم.

class m141204_121823_init_rbac extends Migration
{
    public function up()
    {
        $auth = Yii::$app->authManager;
        $manageArticles = $auth->createPermission('manageArticles');
        $manageArticles->description = 'Manage articles';
        $auth->add($manageArticles);
        $manageUsers = $auth->createPermission('manageUsers');
        $manageUsers->description = 'Manage users';
        $auth->add($manageUsers);
        $moderator = $auth->createRole('moderator');
        $moderator->description = 'Moderator';
        $auth->add($moderator);
        $auth->addChild($moderator, $manageArticles);
        $admin = $auth->createRole('admin');
        $admin->description = 'Administrator';
        $auth->add($admin);
        $auth->addChild($admin, $moderator);
        $auth->addChild($admin, $manageUsers);
    }

    public function down()
    {
        Yii::$app->authManager->removeAll();
    }
}

در کد بالا توسط دو متد createPermission و createRole مجوز و نقش ها رو تعریف کردیم. در پراپرتی description میتونید توضیح کوتاهی در مورد نقش یا مجوزتون قرار بدین با add باید اونها رو به authManager اضافه کنید و با استفاده از متد addChild یک مجوز رو به یک نقش اختصاص بدین(برای تمام مجوز ها باید این کارُ انجام بدین).

از متد assign برای اختصاص دادن مجوز ها به کاربران استفاده میشه در همین migrate میتونید به روش زیر ازش استفاده کنید

$auth->assign($moderator, 2); // user id 2$auth->assign($admin, 1); //  user id 1

نقش ناظم به کاربر با شناسه 2 و نقش مدیر به کاربر با شناسه 1 اختصاص داده شد.

یا اینکه هنگام ثبت کاربر جدید به صورت زیر عمل کنید

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;
} 

برای فهم بهتر این موضوع migration رو up و سری به 4 جدول ذکر شده بزنید.

اطلاعات مربوط به دسترسی ها آماده شده و برای بررسی اینکه آیا کاربر مجوز مورد نظر شما رو داره یا نه میتونید به راحتی از متد can استفاده کنید.

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

یا اینکه میتونید داخل behaviors ها به صورت زیر تعریفش کنید.

namespace app\controllers;

use yii\web\Controller;
use yii\filters\AccessControl;

class ArticleController extends Controller
{
    public function behaviors()
    {
        return [
			'access' => ['
				'class' => AccessControl::className(), 
				'only' => ['suggest', 'queue', 'delete', 'update'], //only be applied to
				'rules' => [
					[
						'allow' => true, 'actions' => ['suggest', 'update'],
						'roles' => ['@'],
						],
					[
						'allow' => true,
						'actions' => ['queue', 'delete'],
						'roles' => ['manageArticles'],
						],
					],
            ],
            'verbs' => [
                'class' => VerbFilter::className(),
                'actions' => ['delete' => ['post'],
                    ],
                ],
            ];
    }
    // ...

موضوع به اینجا ختم نمیشه، یک سیستم مدیریت محتوا با چندین نویسنده رو فرض کنید. ممکنه بخواهید نویسنده ها تنها مطالبی رو بتونن ویرایش کنن که خودشون اونها رو ایجاد کردن یا به عبارت دیگه مالک اون باشن. شاید استفاده از دستور شرطی زیر اینجا کارتونُ راه بندازه اما همیشه اینطور نخواهد بود.

if (\Yii::$app->user->can('updatePost') && $postModel->owner == Yii::$app->user->identity) {
    // update post
}

برای مدیریت این دسترسی ها از قوانین و جدول شماره 4، جدول نگهداری قوانین استفاده میکنیم که بعدا به طور جدا در موردش خواهم نوشت. 

 

 

پیشنهاد

کتاب‌ها

کتاب الگوهای طراحی به بیان ساده(design patterns / دیزاین پترن)

در مهندسی نرم افزار، design patterns(الگوهای طراحی) راه حل‌های قابل استفاده برای مشکلاتی هستند که معمولاً در طراحی نرم‌افزار اتفاق می افتند.

طرح های از پیش ساخته شده‌ای که می‌توانید برای حل مشکلات آن‌ها را سفارشی کنید. شما نمی‌توانید یک الگو را با جستجو در stackoverflow پیدا و در برنامه خود کپی کنید. الگو ها یک قطعه کد خاص نیستند، مفاهیم کلی برای حل مشکلات خاص هستند. شما باید با درک این مفاهیم آن‌ها را در برنامه خود پیاده‌سازی کنید.

کتاب refactoring / ریفکتورینگ

Refactoring مجموعه‌ای از تکنیک‌هاست که به منظور اصلاح و بهبود کدهای قبلی بدون تغییر در عملکرد و رفتارشان جهت خوانایی، کارامدی و قابلیت نگهداری بیشتر انجام می‌شود.

در کتاب Refactoring اثر Martin Fowler نوشته شده: refactoring تکنیک مرتب/منظم سازی برای تجدید ساختار کد موجود است. تغییر ساختار داخلی کد بدون تغییر رفتار خارجی آن.

refactoring یک سرمایه‌گذاری و راه حلی برای مقابله با کد کثیف و بدهی فنی است که باعث کاهش هزینه‌های توسعه نرم‌افزار در آینده خواهد شد.

ارسال نظر

محمدرضا سلطانی در تاریخ 1396/04/10 - 12:17 نوشته
این مورد خط آخر خیلی مهمه. ممنون میشم در این مورد بیشتر توضیح بدی. ضمنا یک سوال. اگر ما سیستمی داشته باشیم که نقش های پیش فرضی مثل موارد بالا رو نداشته باشیم و کاربر مدیر این اختیار رو داشته باشه که بر اساس خود اشخاص نه نقش ها بخواد سطح دسترسی براشون ایجاد کنه اون موقع بهترین کار چیه. فکر میکنم این ساختار rbac جواب نده اونجا. یعنی بخشی رو داشته باشیم برای سطح دسترسی ها و به ازای کارمندان زیرمجموعه بخوایم هر کدوم بخشی از دسترسی ها رو داشته باشن. اگر تعداد بالا باشه بر اساس rbac باید نقش های زیادی رو تعریف کنیم.
پاسخ احسان:

همیشه به طور سیستمی نقش و مجوز وجود داره و با توجه به ابعاد پروزه محدود و مشخصه.

اگر قرار باشه به هر کاربر مجوزهایی تعلق بگیره که به نظرم اینطور زیاد درست نیست rbac به مشکل نمیخوره.