Главная/Статьи/Права и роли в Orchid — гибкая система доступа

Права и роли в Orchid — гибкая система доступа

Настраиваем RBAC в Orchid: роли, permissions, проверка доступа в screens, скрытие элементов. Интеграция с Laravel Gates.

ДМ
Дмитрий Мещеряков
📅 17 июня 2026 г.📖 6 мин чтения

Права в Orchid устроены просто и потому обманчиво: canSee() убирает кнопку, permission() закрывает экран, и всё выглядит защищённым. Между тем разница между «элемент не отображается» и «действие невозможно выполнить» здесь принципиальна, и на ней регулярно строят дырявые админки.

Разберём механизм и, главное, где проходит настоящая граница доступа.

Система прав в Orchid

Orchid предоставляет встроенную систему ролей и разрешений (RBAC):

  • Roles — группы разрешений (Администратор, Модератор, Менеджер)
  • Permissions — конкретные действия (создание статей, управление пользователями)
💡 Совет

Orchid Permissions vs Laravel Gates: Orchid использует свою систему, но она совместима с Laravel. Можно комбинировать оба подхода.

Регистрация разрешений

php
// app/Orchid/PlatformProvider.php
namespace App\Orchid;
use Orchid\Platform\Dashboard;
use Orchid\Platform\ItemPermission;
use Orchid\Platform\OrchidServiceProvider;
class PlatformProvider extends OrchidServiceProvider
{
    public function permissions(): array
    {
        return [
            ItemPermission::group('Система')
                ->addPermission('platform.systems.users', 'Пользователи')
                ->addPermission('platform.systems.roles', 'Роли'),
            ItemPermission::group('Контент')
                ->addPermission('platform.posts.view', 'Просмотр статей')
                ->addPermission('platform.posts.create', 'Создание статей')
                ->addPermission('platform.posts.edit', 'Редактирование статей')
                ->addPermission('platform.posts.delete', 'Удаление статей'),
            ItemPermission::group('Заказы')
                ->addPermission('platform.orders.view', 'Просмотр заказов')
                ->addPermission('platform.orders.manage', 'Управление заказами')
                ->addPermission('platform.orders.export', 'Экспорт заказов'),
            ItemPermission::group('Настройки')
                ->addPermission('platform.settings', 'Настройки сайта'),
        ];
    }
}

Создание ролей

Через UI

Перейдите в /admin/roles и создайте роли:

  • Администратор — все разрешения
  • Контент-менеджер — platform.posts.*
  • Менеджер заказов — platform.orders.*

Через Seeder

php
// database/seeders/RolesSeeder.php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Orchid\Platform\Models\Role;
class RolesSeeder extends Seeder
{
    public function run(): void
    {
        // Администратор
        Role::updateOrCreate(
            ['slug' => 'admin'],
            [
                'name' => 'Администратор',
                'permissions' => [
                    'platform.index' => true,
                    'platform.systems.users' => true,
                    'platform.systems.roles' => true,
                    'platform.posts.view' => true,
                    'platform.posts.create' => true,
                    'platform.posts.edit' => true,
                    'platform.posts.delete' => true,
                    'platform.orders.view' => true,
                    'platform.orders.manage' => true,
                    'platform.orders.export' => true,
                    'platform.settings' => true,
                ],
            ]
        );
        // Контент-менеджер
        Role::updateOrCreate(
            ['slug' => 'content-manager'],
            [
                'name' => 'Контент-менеджер',
                'permissions' => [
                    'platform.index' => true,
                    'platform.posts.view' => true,
                    'platform.posts.create' => true,
                    'platform.posts.edit' => true,
                ],
            ]
        );
        // Менеджер заказов
        Role::updateOrCreate(
            ['slug' => 'order-manager'],
            [
                'name' => 'Менеджер заказов',
                'permissions' => [
                    'platform.index' => true,
                    'platform.orders.view' => true,
                    'platform.orders.manage' => true,
                ],
            ]
        );
    }
}

Проверка прав в Screen

Ограничение всего экрана

php
// app/Orchid/Screens/PostListScreen.php
class PostListScreen extends Screen
{
    /**
     * Требуемые разрешения для доступа
     */
    public function permission(): ?iterable
    {
        return [
            'platform.posts.view',
        ];
    }
    // ...
}

Множественные разрешения

php
public function permission(): ?iterable
{
    return [
        'platform.posts.view',
        'platform.posts.edit',  // Нужны ОБА разрешения
    ];
}
// ИЛИ любое из (через OR в middleware)

Скрытие элементов по правам

⚠️ Важно

canSee() — это про интерфейс, а не про доступ. Он убирает кнопку из разметки. Метод-обработчик, который эта кнопка вызывала, остаётся доступным: он привязан к экрану, и отправить запрос на его выполнение можно напрямую, минуя интерфейс.

То есть пользователь без права на удаление не видит кнопку «Удалить» — и при этом может выполнить удаление, если знает имя метода. Знать его несложно: имена методов предсказуемы, а разметка соседних экранов подсказывает соглашения.

Проверка прав обязана быть внутри метода:

php
public function remove(Order $order)
{
    abort_unless(Auth::user()->hasAccess('platform.orders.delete'), 403);

    $order->delete();

    Toast::info('Заказ удалён');
}

canSee() при этом остаётся нужным — он избавляет оператора от кнопок, которыми тот не может воспользоваться. Но это удобство, а не защита.

Кнопки в commandBar

php
public function commandBar(): iterable
{
    return [
        Link::make('Создать')
            ->icon('plus')
            ->route('platform.post.edit')
            ->canSee(auth()->user()->hasAccess('platform.posts.create')),
        Button::make('Удалить')
            ->icon('trash')
            ->method('delete')
            ->canSee(auth()->user()->hasAccess('platform.posts.delete')),
        Button::make('Экспорт')
            ->icon('cloud-download')
            ->method('export')
            ->canSee(auth()->user()->hasAnyAccess([
                'platform.orders.export',
                'platform.admin',
            ])),
    ];
}

Колонки в таблице

php
public function layout(): iterable
{
    return [
        Layout::table('posts', [
            TD::make('title', 'Заголовок'),
            TD::make('actions')
                ->canSee(auth()->user()->hasAccess('platform.posts.edit'))
                ->render(fn($post) => Link::make('Редактировать')
                    ->route('platform.post.edit', $post)),
        ]),
    ];
}

Поля в форме

php
public function layout(): iterable
{
    return [
        Layout::rows([
            Input::make('post.title')
                ->title('Заголовок'),
            // Только админы могут менять автора
            Select::make('post.author_id')
                ->fromModel(User::class, 'name')
                ->title('Автор')
                ->canSee(auth()->user()->hasAccess('platform.admin')),
            // Только с правом публикации
            Switcher::make('post.is_published')
                ->title('Опубликовать')
                ->canSee(auth()->user()->hasAccess('platform.posts.publish')),
        ]),
    ];
}

Меню по правам

php
// app/Orchid/PlatformProvider.php
public function menu(): array
{
    return [
        Menu::make('Статьи')
            ->icon('docs')
            ->route('platform.post.list')
            ->permission('platform.posts.view'),
        Menu::make('Заказы')
            ->icon('bag')
            ->route('platform.orders.list')
            ->permission('platform.orders.view'),
        Menu::make('Пользователи')
            ->icon('people')
            ->route('platform.systems.users')
            ->permission('platform.systems.users'),
        Menu::make('Настройки')
            ->icon('settings')
            ->permission('platform.settings')
            ->list([
                Menu::make('Общие')
                    ->route('platform.settings.general'),
                Menu::make('SEO')
                    ->route('platform.settings.seo'),
            ]),
    ];
}

Интеграция с Laravel Gates

php
// app/Providers/AuthServiceProvider.php
use Illuminate\Support\Facades\Gate;
public function boot(): void
{
    // Orchid permissions как Gates
    Gate::before(function ($user, $ability) {
        if ($user->hasAccess($ability)) {
            return true;
        }
    });
    // Дополнительные Gates
    Gate::define('edit-post', function ($user, $post) {
        return $user->id === $post->author_id 
            || $user->hasAccess('platform.posts.edit-any');
    });
}
php
// Использование в Screen
public function layout(): iterable
{
    return [
        Layout::rows([
            Input::make('post.title')
                ->canSee(Gate::allows('edit-post', $this->post)),
        ]),
    ];
}

Проверка в методах Screen

php
public function delete(Post $post): void
{
    // Проверка прав
    if (!auth()->user()->hasAccess('platform.posts.delete')) {
        Toast::error('Недостаточно прав');
        return;
    }
    // Или через Gate
    $this->authorize('delete', $post);
    $post->delete();
    Toast::info('Статья удалена');
}

Middleware для роутов

php
// routes/platform.php
use Tabuna\Breadcrumbs\Trail;
// Группа с проверкой прав
Route::middleware(['platform.access:platform.orders.view'])
    ->group(function () {
        Route::screen('orders', OrderListScreen::class)
            ->name('platform.orders.list');
        Route::screen('orders/{order}', OrderEditScreen::class)
            ->name('platform.orders.edit')
            ->middleware('platform.access:platform.orders.manage');
    });
⚠️ Важно

Не забывайте о backend! canSee() только скрывает UI. Всегда проверяйте права в методах screen (delete, save и т.д.) — злоумышленник может отправить запрос напрямую.

Команды для управления

bash
# Создать админа
php artisan orchid:admin admin admin@example.com password
# Список пользователей
php artisan orchid:table
# Сбросить кэш разрешений
php artisan cache:clear

Итоги

МетодНазначение
permission()Ограничить доступ ко всему Screen
canSee()Скрыть элемент по условию
hasAccess()Проверить одно разрешение
hasAnyAccess()Проверить любое из разрешений

Правила работы с правами.

Проверка в методе — обязательна, скрытие в интерфейсе — желательно. Именно в таком порядке приоритета. Экран без canSee() неудобен; метод без проверки прав — уязвим.

Права описывают действия, а не роли. platform.orders.delete, а не isManager(). Роль — это набор прав, который меняется по решению бизнеса; проверка роли в коде означает, что каждое такое решение требует правки кода и выкладки.

Проверяйте право на конкретный объект, а не только на действие. «Может редактировать заказы» и «может редактировать этот заказ» — разные вопросы. Идентификатор объекта приходит из запроса, и менеджер, имеющий доступ к своим заказам, при отсутствии второй проверки открывает чужие простой подменой числа в адресе.

Регистрируйте все разрешения в одном месте и группируйте по разделам — иначе через год никто не сможет ответить, что означает конкретная галочка в настройках роли.

Не забывайте про массовые действия и экспорт. Кнопка «Выгрузить в Excel» на экране со списком часто остаётся без проверки прав, хотя выгружает ровно те же данные, доступ к которым вы ограничивали в других местах.

💡 Совет

Способ проверить админку за десять минут. Заведите тестовую учётную запись с минимальными правами, войдите под ней и попробуйте выполнить действия, которых в интерфейсе не видно, — отправив запрос на соответствующий метод вручную (инструменты разработчика в браузере позволяют повторить запрос с изменёнными параметрами). Это самая быстрая проверка того, что права реально работают, а не только прячут кнопки. Проходить её стоит после каждого крупного изменения в админке.

🚀

Хотите такое же решение?

Настрою окружение под ваш проект, учту специфику инфраструктуры и обучу команду.

Обсудить проект →
Бесплатная консультация · Ответ в течение дня

Комментарии

Система комментариев скоро будет подключена. А пока вы можете написать мне в Telegram или на email.