callcocam/inertia-rbac
Composer 安装命令:
composer require callcocam/inertia-rbac
包简介
RBAC (roles & permissions) para Laravel + Inertia + Vue, com ULID, catálogo de permissões como fonte única e Wayfinder para o frontend.
README 文档
README
RBAC (roles & permissions) para Laravel + Inertia + Vue, construído sobre o
spatie/laravel-permission com:
- ULID em roles, permissions, pivots e morph keys.
- Catálogo de permissões como fonte única (
PermissionName), com metadata PT-BR. - Controllers no pacote (CRUD +
sync) — o app não copia controller. - Páginas Vue no projeto — o pacote não traz
.vue; você cria os componentes no visual do seu app e as ações usam os controllers do pacote via Wayfinder. - Teams (multi-tenant) opcional, reaproveitando a config de teams do Spatie.
- Rollout gradual (
rbac.enabled) e super-admin porsystem_name.
Filosofia: visual do projeto, ações do pacote. O HTML/estilo é 100% seu; o endpoint que processa cada ação é o controller do pacote.
Requisitos
- PHP 8.3+
- Laravel 12+/13+
- Inertia v2+ (
@inertiajs/vue3) spatie/laravel-permission^8.0 (instalado como dependência)
Instalação
composer require callcocam/inertia-rbac # Config do pacote (só o específico do RBAC — o resto reusa o config do Spatie) php artisan vendor:publish --tag=rbac-config # Migrations com ULID (config-driven) php artisan vendor:publish --tag=rbac-migrations # (opcional) publicar o config do Spatie, se quiser editá-lo à mão php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" --tag=permission-config php artisan migrate php artisan rbac:sync # popula as permissões do catálogo # roles de sistema (super-admin, admin) — publique o seeder e rode: php artisan vendor:publish --tag=rbac-seeders php artisan db:seed --class="Database\Seeders\RbacSeeder"
Reaproveitando a config do Spatie
O pacote alinha automaticamente o config/permission.php do Spatie no boot:
permission.models.role→Callcocam\InertiaRbac\Models\Rolepermission.models.permission→Callcocam\InertiaRbac\Models\Permission- quando
rbac.teams.enabled = true: ligapermission.teamse definepermission.column_names.team_foreign_keya partir derbac.teams.foreign_key.
Ou seja: tabelas, colunas, cache, guards e teams core continuam no Spatie; o
config/rbac.php só cobre views Vue, rollout, roles protegidas, redirects e rotas.
Preparar o model User
use Callcocam\InertiaRbac\Concerns\HasRbac; class User extends Authenticatable { use HasRbac; // HasRoles (Spatie) + HasUlids + isSuperAdmin() }
O
iddo User deve ser ULID (as morph keys do RBAC são ULID).
Declarar as permissões do seu app
O catálogo do pacote traz só as permissões de gestão (roles.*, permissions.*).
As suas você declara em config/rbac.php — PermissionName::all() mescla as duas:
// config/rbac.php 'permissions' => [ 'products.viewAny', 'products.view', 'products.create', 'products.update', 'products.delete', 'orders.viewAny', 'orders.view', ], // opcional: classificar recursos por tipo/contexto 'type_map' => ['products' => 'catalog', 'orders' => 'sales'],
Depois rode php artisan rbac:sync (ou o botão de sync na tela de permissões).
Policies dos recursos do seu app
Use o trait do pacote, que já respeita o rollout (rbac.enabled) e o super-admin:
use Callcocam\InertiaRbac\Concerns\ChecksRbacPermission; class ProductPolicy { use ChecksRbacPermission; public function viewAny($user): bool { return $this->allowByContext($user, 'products.viewAny'); } public function create($user): bool { return $this->allowByContext($user, 'products.create'); } // ... }
O Gate::before de super-admin (por system_name) já é registrado pelo pacote.
Páginas Vue (criadas no seu projeto)
O pacote não traz .vue. Crie os componentes nos caminhos de
config('rbac.views.*') (default abaixo) em resources/js/pages/:
| Config | Componente default |
|---|---|
rbac.views.roles.index |
rbac/roles/Index |
rbac.views.roles.form |
rbac/roles/Form |
rbac.views.permissions.index |
rbac/permissions/Index |
rbac.views.permissions.form |
rbac/permissions/Form |
Publique os stubs de referência e adapte ao visual do seu app:
php artisan vendor:publish --tag=rbac-stubs
# copia para base_path('stubs/inertia-rbac/...') — use como ponto de partida
Pontos-chave dos stubs:
- Index: paginator chega como prop deferida (
<Deferred>+ skeleton). Botão "Novo" comv-if="can.create". Excluir por linha só comv-if="!row.is_protected". - Form: um único componente para create e edit;
system_name/nameimutáveis no edit; picker de permissões portype.
Wayfinder — ligando a UI às rotas do pacote
As ações nunca montam URL na mão: usam helpers gerados pelo
laravel/wayfinder a partir das rotas
nomeadas do pacote (rbac.roles.*, rbac.permissions.*).
composer require laravel/wayfinder --dev npm install -D @laravel/vite-plugin-wayfinder
// vite.config.ts import { wayfinder } from '@laravel/vite-plugin-wayfinder' export default defineConfig({ plugins: [/* laravel(), vue(), */ wayfinder({ formVariants: true })], })
php artisan wayfinder:generate --with-form
import RoleController from '@/actions/Callcocam/InertiaRbac/Http/Controllers/RoleController' RoleController.index.url() // GET index RoleController.edit.url(role.id) // GET edit // <Form v-bind="RoleController.store.form()"> (create) // <Form v-bind="RoleController.update.form(role.id)"> (edit)
Se o gerador não rastrear os controllers do vendor, veja o fallback na seção "Wayfinder" do arquivo
PROMPT.md.
Mostrar/esconder (server-driven)
- Botões por página: cada
indexjá enviacan: { create: boolean }. Usev-if="can.create". Ações de linha:v-if="!row.is_protected". - Menu: decida os itens no servidor com o
PermissionResolver:
use Callcocam\InertiaRbac\Support\PermissionResolver; use Callcocam\InertiaRbac\Models\Role; $resolver = app(PermissionResolver::class); $menu = array_values(array_filter([ $resolver->allows($user, 'viewAny', Role::class) ? ['label' => 'Papéis', 'href' => RoleController::index()] : null, ]));
Assim os itens não autorizados nem chegam ao cliente.
Configuração (config/rbac.php)
| Chave | Para quê |
|---|---|
enabled |
Liga/desliga a checagem (rollout gradual). |
guard |
Guard das roles/permissions. |
connection |
Conexão isolada (ex.: landlord), ou null. |
teams.enabled / teams.foreign_key |
Multi-tenant (espelha para o Spatie). |
protected_roles / protected_permissions |
Não podem ser apagadas/renomeadas. |
super_admin_role |
system_name da role com Gate::before. |
permissions / type_map |
Catálogo do app + classificação por tipo. |
views.* |
Caminhos dos componentes Vue. |
routes.* / redirect.* |
Prefixo, nome, middleware e redirects. |
per_page |
Paginação das telas. |
Teams / multi-tenant (escopo de permissões por tenant)
O nome "teams" vem do Spatie e pode confundir: não é um recurso de "grupos de usuários", e o Laravel não tem teams nativo.
rbac.teamsliga a teams feature do Spatie = escopo de permissões por tenant: adiciona uma colunateam_foreign_keyemroles/model_has_*para você ter roles/permissões diferentes por tenant. Não cria tabelateamsnem modelTeam. Por isso não conflita com nada do framework.
Está desligado por padrão (single-tenant). Para ligar:
// config/rbac.php 'teams' => [ 'enabled' => true, 'foreign_key' => 'tenant_id', // coluna de tenant nas tabelas do Spatie 'resolver' => fn ($request) => $request->user()?->tenant_id, // null = lê a foreign_key do usuário ],
Isso liga o middleware SetPermissionTeamContext no grupo de rotas e espelha
permission.teams / permission.column_names.team_foreign_key. A resolução do
tenant atual é do app (por padrão o middleware lê a foreign_key do usuário
autenticado; use resolver para buscar de outro lugar).
O Spatie suporta um
team_foreign_keyglobal. Se o app já usa a teams feature do Spatie para outra coisa, os dois precisam concordar no mesmo nome de coluna.
Testes
composer test # Pest + Orchestra Testbench (SQLite em memória) composer format # Laravel Pint
Licença
MIT. Veja LICENSE.md.
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 2
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-07-09