ACL

ACL مخفف عبارت Access Control List به معنی «فهرست کنترل دسترسی» است.

- دسترسی‌های ACL جوملا (Joomla ACL Access) مربوط می‌شود به اینکه کاربران چه چیزهایی را می‌توانند مشاهده کنند.

- مجوزهای ACL جوملا (Joomla ACL Permissions) مربوط می‌شود به اینکه کاربران چه کارهایی می‌توانند انجام دهند.

چگونه دسترسی در جوملا کار می‌کند

مواردی مانند مقاله‌ها (Articles)، مخاطبین (Contacts) و آیتم‌های منو (Menuitems) در جوملا دارای یک فیلد به نام Access هستند که برای تعیین این به‌کار می‌رود که آیا یک کاربر ممکن است آن مورد را مشاهده کند یا خیر.

مقدار فیلد Access که به آن سطح دسترسی مشاهده (Viewing Access Level) گفته می‌شود، در واقع یک عدد صحیح (integer) است که به نام مشخصی متصل است؛ این نام‌های سطح دسترسی را می‌توانید در بخش مدیریت جوملا، در منوی کاربران / سطوح دسترسی ( Users / Access Levels ) مشاهده کنید.

در همان فرم (صفحه مدیریت سطوح دسترسی) می‌توانید گروه‌های کاربری را ببینید که به آن سطح دسترسی امکان مشاهده می‌دهند. مدیر سایت مشخص می‌کند که کدام گروه‌های کاربری اجازه دارند آیتم‌هایی با آن سطح دسترسی را ببینند.

هنگامی که مدیر یک رکورد کاربری را ویرایش می‌کند، می‌تواند در تب «گروه‌های کاربری اختصاص داده شده» (Assigned User Groups) گروه‌های کاربری که آن کاربر به آن‌ها تعلق دارد را تنظیم کند. گروه‌های کاربری دارای ساختار سلسله‌مراتبی (درختی) هستند، بنابراین اگر کاربر به گروهی تعلق داشته باشد که خود آن زیرمجموعه (فرزند) گروه دیگری باشد، آن کاربر عضو گروه بالادستی (پدر) آن نیز هست.

به عنوان مثال، در گروه‌های کاربری پیش‌فرض جوملا، گروه کاربری «مدیر سایت» (Administrator) زیرمجموعه گروه «مدیر» (Manager) است؛ پس کاربری که گروه Administrator به او اختصاص داده شده باشد، به شکل خودکار عضو گروه Manager هم هست.

سطوح دسترسی در جوملا

سطوح دسترسی در جوملا

با توجه به نموداری که فرض می‌کنیم (تصویر مشابه متن اصلی)، فرض کنید کاربر به گروه‌های کاربری (ستون‌ها) A، C و D تعلق دارد. کاربر ممکن است به طور مستقیم به برخی از این گروه‌ها اختصاص یافته باشد یا به واسطه سلسله مراتب گروه‌ها (والد و فرزند) عضو آن باشد.

لوزی های رنگی در نمودار نشانگر سطوح دسترسی مختلف سایت جوملا هستند.

سطح دسترسی آبی روشن اجازه مشاهده برای گروه‌های کاربری A, D و E را می‌دهد.

چون کاربر عضو گروه‌های A و D است، هر آیتمی که سطح دسترسی آبی روشن داشته باشد، باید برای این کاربر قابل مشاهده باشد.

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

 

سطح دسترسی قرمز فقط اجازه مشاهده برای گروه کاربری E را می‌دهد.

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

با این روش، کاربر باید بتواند آیتم شماره ۵ را ببیند، اما آیتم‌های شماره ۳ و ۴ برای او قابل مشاهده نباشد.

رویکرد برنامه‌نویسی (کدگذاری) در بررسی دسترسی

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

ساده‌ترین روش برای بررسی دسترسی در کد شما استفاده از تابع `getAuthorisedViewLevels` از کلاس User است:

 
$user = Factory::getApplication()->getIdentity();  
$levels = $user->getAuthorisedViewLevels();

 

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

(توجه داشته باشید که گاهی در کد جوملا ممکن است مشاهده کنید که متغیری به نام `$groups` به این شکل مقداردهی می‌شود:

 
$groups = $user->getAuthorisedViewLevels();

 

که این ممکن است باعث شود فکر کنید این تابع آرایه‌ای از گروه‌های کاربری باز می‌گرداند؛ اما این درست نیست و این نوع نام‌گذاری کمی گمراه‌کننده است.)

چک کردن اجازه مشاهده یک آیتم

برای بررسی اینکه آیا یک کاربر می‌تواند آیتم خاصی را ببیند، باید مقدار فیلد Access آن آیتم را بگیرید و بررسی کنید که آیا این مقدار در آرایه برگشتی از `getAuthorisedViewLevels` است یا خیر، مانند مثال زیر:

 
$levels = $user->getAuthorisedViewLevels();
$canView = in_array($item->access, $levels);

 

استثنا برای کاربران فوق‌العاده (Super Users)

توجه داشته باشید که کاربران با دسترسی «سوپر یوزر» (Super User) باید بتوانند همه آیتم‌ها را ببینند، صرف‌نظر از سطح دسترسی. بنابراین معمولاً یک شرط دیگر برای این کاربران اضافه می‌شود:

 
if ($user->authorise('core.admin')) {  
    // این کاربر سوپر یوزر است — اجازه مشاهده آیتم داده می‌شود  
}
 

 

نحوه برخورد در صورت عدم دسترسی

اگر کاربر اجازه مشاهده آیتم را نداشت، باید تصمیم بگیرید بهترین رفتار چیست:

- اگر کاربر وارد شده (login) است، بهتر است یک وضعیت HTTP با کد 403 (ممنوع) برگردانید.

- اگر کاربر وارد نشده است، هم می‌توانید کد 403 بازگردانید، یا بهتر است او را به صفحه ورود هدایت کنید و پیغام دهید برای دیدن آن محتوا باید وارد سیستم شود.

می‌توانید با چک کردن خاصیت `guest` از شیء User متوجه شوید که کاربر وارد شده است یا خیر. برای مثال، اگر کاربر مهمان باشد، با پیغام خطای «عدم اجازه» یک خطای 403 پرتاب می‌کنید:

 
if ($user->guest) {  
    throw new \Exception(Text::_('JERROR_ALERTNOAUTHOR'), 403);  
}

 

مجوزها (Permissions)

جوملا یک چارچوب بسیار پیشرفته و پیچیده برای مجوزها دارد و اگر با آن آشنایی ندارید، بهتر است ابتدا مقدمه‌ها و آموزش‌های ابتدایی را مشاهده کنید. من توصیه می‌کنم ابتدا آموزش Access Control List Tutorial و ویدئوی  Joomla 3 ACL Explained with Randy Carey (از دقیقه 2 تا 32 بخش مهم آن است) را ببینید. هرچند این آموزش‌ها مربوط به جوملا ۳ هستند، اما سیستم ACL بین جوملا ۳، ۴ و ۵ تغییر خاصی نداشته است.

نگاهی از منظر پیاده‌سازی به مجوزها

مجوزها در جدول `#__assets` جوملا نگهداری می‌شوند، در ستون `rules`. اگر جوملای شما تازه نصب شده باشد، در رکورد مربوط به `com_content` (یعنی رکوردی که مقدار ستون `name` آن "com_content" است) یک مقدار در ستون `rules` مشابه رشته‌ی JSON زیر خواهید داشت (ممکن است دقیقاً عین همین نباشد ولی ساختار مشابه دارد):

 
{  
  "core.admin":{"7":1},  
  "core.manage":{"6":1},  
  "core.create":{"3":1},  
  "core.edit":{"4":1,"2":1},  
  "core.edit.state":{"5":1},  
  "core.execute.transition":{"6":1,"5":1},  
  "core.delete":{"2":0}  
}
 

 این رشته JSON به این معنی است که در سطح `com_content`:

- برای مجوز `"core.admin"`، گروه کاربری شماره ۷ مقدار ۱ (مجاز) دارد.

- برای `"core.manage"`، گروه کاربری ۶ مقدار ۱ (مجاز) دارد.

- برای بقیه‌ی مجوزها به همین صورت...

- برای `"core.delete"`، گروه کاربری ۲ مقدار ۰ (ممنوع) دارد.

اگر گروه کاربری برای مجوزی مشخص نشده باشد (مثلاً در JSON بالا گروهی وجود ندارد)، یعنی مقدار آن ارث‌بری (Inherited) است و از سطح بالاتر گرفته می‌شود.

مقادیر بالا بازتابی از پیکربندی سیستم بخش مقاله‌ها در تب مجوزها (Permissions) هستند.

مثال واقعی از مجوزها در جوملا

مثال واقعی از مجوزها در جوملا

در تصویر اشاره شده، مجوزهای گروه کاربران Registered با شناسه گروه کاربری "2" نشان داده شده است.

تنظیمات من به این صورت است که:

- `"core.edit"` مقدار ۱ (مجاز) دارد.

- `"core.delete"` مقدار ۰ (ممنوع) دارد.

- بقیه مجوزها تنظیم نشده‌اند و به صورت پیش‌فرض به ارث‌برده شده هستند.

 اکشن‌های مجوز (Permission Actions)

این‌ها نوع اعمالی هستند که کاربران ممکن است انجام دهند. بسیاری از آنها واضح هستند اما برخی نیاز به توضیح کوتاه دارند:

- core.admin

  در سطح پیکربندی یک افزونه به معنی «پیکربندی ACL و گزینه‌ها» است و در سطح پیکربندی کلی (Global Configuration) به معنی «سوپر یوزر» است. 

  کاربری که در سطح کامپوننت مجوز core.admin دارد ولی در سطح سایت ندارد، می‌تواند هر کاری مربوط به آن کامپوننت انجام دهد ولی دسترسی‌های سطح کل سایت به او داده نمی‌شود. 

  کاربری که در سطح سایت دارای مجوز core.admin است، کامل و بدون محدودیت دسترسی دارد و می‌تواند در کل سایت هر کاری انجام دهد.

- core.options 

به معنی «پیکربندی گزینه‌ها» است. مشخص می‌کند که کاربر می‌تواند گزینه‌های: 

  • تنظیمات کلی سایت (Global Configuration) را پیکربندی کند (اگر مجوز در سطح عمومی داشته باشد) 
  • یا فقط گزینه‌های یک کامپوننت خاص را پیکربندی کند (اگر مجوز در سطح آن کامپوننت داده شده باشد)

- core.manage

  به معنی «دسترسی به رابط مدیریت (ادمین)» است. کاربری که این مجوز را دارد می‌تواند وارد بخش مدیریت شود و عملیات ابتدایی مدیریت مثل بررسی آیتم‌ها را انجام دهد.

سلسله مراتب دارایی‌ها (Asset Hierarchy)

Joomla Asset Hierarchy

در جوملا، دارایی‌ها (assets) در یک سلسله مراتب نگهداری می‌شوند که با استفاده از ساختار Nested Set در جدول `#__assets` پیاده‌سازی شده است. این ساختار اجازه می‌دهد مجوزها در سطوح بالاتر تعریف شوند و به طور خودکار به آیتم‌های سطوح پایین‌تر منتقل (رپل) شوند.

برای کامپوننت `com_content` سطح پایین‌ترین دارایی، مقاله‌ی جداگانه (مثلاً یک مقاله خاص) است. سپس به سمت بالا می‌رود به:

- دسته‌بندی مقاله

- والد آن دسته‌بندی (و همینطور به بالا تا دسته والد نهایی)

- مجوزهای سطح `com_content`

- مجوزهای سطح پیکربندی کلی سایت (Global Configuration)

چگونه جوملا تعیین می‌کند که آیا یک کاربر مجاز است عملی را انجام دهد؟

فرض کنید قصد داریم بررسی کنیم که آیا کاربر می‌تواند یک مقاله را ویرایش کند (permission مورد نظر: `"core.edit"`). روند بررسی به صورت منطقی (نه دقیقاً شکل کد پیاده شده، که بهینه‌تر است) به شرح زیر است:

1. در ابتدا مجوز (permission) مورد نظر را مشخص می‌کنیم، مثلاً `"core.edit"`.

2. تمام گروه‌های کاربری که کاربر به آن‌ها تعلق دارد پیدا می‌شوند. این شامل گروه‌های اختصاص داده شده مستقیم به کاربر و همچنین گروه‌های پدر (ارث‌بری) آن‌ها خواهد بود.

3. قوانین مجوز برای مقاله مورد نظر را می‌گیریم. برای مثال اگر شناسه مقاله ۲۲ باشد، رکورد دارایی که مقدار `name` آن `"com_content.article.22"` است را جستجو و مقدار ستون `rules` آن را بررسی می‌کنیم.

4. از طریق فیلد `parent` در جدول دارایی‌ها، به بالا در سلسله مراتب می‌رویم و قوانین مجوزهای همه‌ی دارایی‌های (assets) بالا دستی (پدران) این مقاله را نیز دریافت می‌کنیم. این مسیر از دسته‌بندی‌ها، سپس `com_content` و در نهایت سطح پیکربندی کلی سایت (Global Configuration) ادامه دارد.

5. در این مجموعه قوانین، برای هر گروه کاربری که کاربر به آن تعلق دارد، به دنبال مجوز `"core.edit"` می‌گردیم:

- اگر در هر سطح از سلسله مراتب، برای هر گروه کاربری کاربر، مقدار ۰ (ممنوع یا Denied) پیدا شود، کاربر اجازه انجام این عمل را ندارد. یعنی اگر در هر جای سلسله مراتب، یکی از گروه‌های کاربر به شکل صریح رد شده باشد، کل دسترسی رد می‌شود.

- اگر هیچ مقدار منع شده‌ای (۰) پیدا نشود و حداقل یک مورد برای یکی از گروه‌های کاربری کاربر با مقدار ۱ (مجاز یا Allowed) وجود داشته باشد، کاربر اجازه انجام آن عمل را خواهد داشت.

- اگر هیچ ورودی (Entry) مرتبط با مجوز مورد نظر برای هیچ یک از گروه‌های کاربری کاربر وجود نداشته باشد، کاربر اجازه انجام آن عمل را ندارد.

بررسی مجوزها در افزونه شما

جوملا به صورت خودکار مجوزها را برای کنترل اعمال کاربر در افزونه‌ی شما اعمال نمی‌کند. شما باید مشخص کنید که برای هر عملی، کدام رشته مجوز (permission string) مناسب است و از توابع کتابخانه جوملا استفاده کنید تا بررسی کنید آیا کاربر اجازه انجام آن را دارد یا خیر.

مثال: بررسی اینکه آیا کاربر اجازه ویرایش یک مقاله با شناسه `22` را دارد:

 
$user = Factory::getApplication()->getIdentity();
$allowed = $user->authorise('core.edit', 'com_content.article.22');

 

متغیر `$allowed` مقداری `true` یا `false` خواهد داشت که نشان می‌دهد کاربر اجازه انجام این عمل را دارد یا خیر.

مثال دیگر: بررسی اینکه آیا کاربر اجازه ایجاد یک تماس دارد:

 

$allowed = $user->authorise('core.create', 'com_contact');

 

اگر بخواهید چندین مجوز را در سطح کامپوننت بررسی کنید (مثلاً برای نمایش دکمه‌های مربوط در یک نمای کامپوننت)، می‌توانید از کلاس `ContentHelper` به این صورت استفاده کنید:

 
use Joomla\CMS\Helper\ContentHelper;
…
$canDo = ContentHelper::getActions('com_example');
if ($canDo->get('core.create')) {  // display New button
}
if ($canDo->get('core.delete')) {  // display Delete button
}  // etc