home / skills / victorsmaniotto / degestao / auth-rbac

auth-rbac skill

/.agent/skills/auth-rbac

npx playbooks add skill victorsmaniotto/degestao --skill auth-rbac

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
17.5 KB
---
name: auth-rbac
description: Implementação de autenticação e controle de acesso baseado em roles (RBAC) em Laravel incluindo Guards, Policies, Gates, Permissions, Middleware de autorização, e integração com pacotes como Spatie Permission. Usar para implementar login/registro, controle de acesso por perfil, permissões granulares, proteção de rotas, e auditoria de acessos.
---

# Auth RBAC

Skill para autenticação e controle de acesso baseado em roles em Laravel.

## Conceitos Fundamentais

```
┌─────────────────────────────────────────────────────────────┐
│                    HIERARQUIA RBAC                          │
├─────────────────────────────────────────────────────────────┤
│  USER ──┬── ROLE ──┬── PERMISSION                          │
│         │          │                                        │
│  João ──┼── Admin ─┼── users.create                        │
│         │          ├── users.edit                          │
│         │          ├── users.delete                        │
│         │          └── contracts.*                         │
│         │                                                   │
│  Maria ─┼── Manager ┼── users.view                         │
│         │           ├── contracts.create                   │
│         │           └── contracts.edit                     │
│         │                                                   │
│  Pedro ─┴── Viewer ─┴── *.view                             │
└─────────────────────────────────────────────────────────────┘
```

## Setup com Spatie Permission

```bash
# Instalar pacote
composer require spatie/laravel-permission

# Publicar migrations e config
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"

# Rodar migrations
php artisan migrate
```

### Configurar Model User

```php
<?php

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable
{
    use HasRoles;

    // ...
}
```

### Criar Roles e Permissions

```php
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;

class RolesAndPermissionsSeeder extends Seeder
{
    public function run(): void
    {
        // Reset cached roles and permissions
        app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();

        // Criar permissions
        $permissions = [
            // Users
            'users.view',
            'users.create',
            'users.edit',
            'users.delete',
            
            // Contracts
            'contracts.view',
            'contracts.create',
            'contracts.edit',
            'contracts.delete',
            'contracts.approve',
            
            // Payments
            'payments.view',
            'payments.create',
            'payments.process',
            
            // Reports
            'reports.view',
            'reports.export',
            
            // Settings
            'settings.view',
            'settings.edit',
        ];

        foreach ($permissions as $permission) {
            Permission::create(['name' => $permission]);
        }

        // Criar roles e atribuir permissions
        
        // Super Admin - todas as permissões
        $superAdmin = Role::create(['name' => 'super-admin']);
        $superAdmin->givePermissionTo(Permission::all());

        // Admin - quase tudo, exceto settings
        $admin = Role::create(['name' => 'admin']);
        $admin->givePermissionTo([
            'users.view', 'users.create', 'users.edit',
            'contracts.view', 'contracts.create', 'contracts.edit', 'contracts.delete', 'contracts.approve',
            'payments.view', 'payments.create', 'payments.process',
            'reports.view', 'reports.export',
        ]);

        // Manager - gerencia contratos e pagamentos
        $manager = Role::create(['name' => 'manager']);
        $manager->givePermissionTo([
            'users.view',
            'contracts.view', 'contracts.create', 'contracts.edit',
            'payments.view', 'payments.create',
            'reports.view',
        ]);

        // Operator - operações básicas
        $operator = Role::create(['name' => 'operator']);
        $operator->givePermissionTo([
            'contracts.view', 'contracts.create',
            'payments.view',
        ]);

        // Viewer - apenas visualização
        $viewer = Role::create(['name' => 'viewer']);
        $viewer->givePermissionTo([
            'contracts.view',
            'payments.view',
            'reports.view',
        ]);

        // Criar super admin inicial
        $user = \App\Models\User::factory()->create([
            'name' => 'Super Admin',
            'email' => '[email protected]',
        ]);
        $user->assignRole('super-admin');
    }
}
```

## Gates e Policies

### Definir Gates

```php
<?php
// app/Providers/AuthServiceProvider.php

namespace App\Providers;

use App\Models\Contract;
use App\Models\User;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;

class AuthServiceProvider extends ServiceProvider
{
    protected $policies = [
        Contract::class => \App\Policies\ContractPolicy::class,
    ];

    public function boot(): void
    {
        // Super admin bypassa todas as verificações
        Gate::before(function (User $user, string $ability) {
            if ($user->hasRole('super-admin')) {
                return true;
            }
        });

        // Gates customizados
        Gate::define('access-admin', function (User $user) {
            return $user->hasAnyRole(['super-admin', 'admin']);
        });

        Gate::define('view-reports', function (User $user) {
            return $user->hasPermissionTo('reports.view');
        });

        Gate::define('manage-team', function (User $user) {
            return $user->hasAnyRole(['super-admin', 'admin', 'manager']);
        });
    }
}
```

### Criar Policy

```php
<?php

namespace App\Policies;

use App\Models\Contract;
use App\Models\User;

class ContractPolicy
{
    /**
     * Antes de qualquer verificação
     */
    public function before(User $user, string $ability): ?bool
    {
        if ($user->hasRole('super-admin')) {
            return true;
        }
        return null; // Continua para os métodos específicos
    }

    /**
     * Pode listar contratos?
     */
    public function viewAny(User $user): bool
    {
        return $user->hasPermissionTo('contracts.view');
    }

    /**
     * Pode ver este contrato específico?
     */
    public function view(User $user, Contract $contract): bool
    {
        // Pode ver se tem permissão OU se é dono do contrato
        return $user->hasPermissionTo('contracts.view')
            || $contract->user_id === $user->id;
    }

    /**
     * Pode criar contratos?
     */
    public function create(User $user): bool
    {
        return $user->hasPermissionTo('contracts.create');
    }

    /**
     * Pode editar este contrato?
     */
    public function update(User $user, Contract $contract): bool
    {
        // Não pode editar contratos finalizados
        if ($contract->status === 'completed') {
            return false;
        }

        return $user->hasPermissionTo('contracts.edit')
            || $contract->user_id === $user->id;
    }

    /**
     * Pode excluir este contrato?
     */
    public function delete(User $user, Contract $contract): bool
    {
        // Só admin pode excluir
        return $user->hasPermissionTo('contracts.delete');
    }

    /**
     * Pode aprovar este contrato?
     */
    public function approve(User $user, Contract $contract): bool
    {
        // Não pode aprovar próprio contrato
        if ($contract->user_id === $user->id) {
            return false;
        }

        return $user->hasPermissionTo('contracts.approve');
    }
}
```

## Middleware de Autorização

### Registrar Middleware

```php
<?php
// bootstrap/app.php (Laravel 11)

->withMiddleware(function (Middleware $middleware) {
    $middleware->alias([
        'role' => \Spatie\Permission\Middleware\RoleMiddleware::class,
        'permission' => \Spatie\Permission\Middleware\PermissionMiddleware::class,
        'role_or_permission' => \Spatie\Permission\Middleware\RoleOrPermissionMiddleware::class,
    ]);
})
```

### Proteger Rotas

```php
<?php
// routes/web.php

use Illuminate\Support\Facades\Route;

// Área administrativa - requer role admin
Route::middleware(['auth', 'role:admin|super-admin'])->prefix('admin')->group(function () {
    Route::get('/dashboard', [AdminController::class, 'dashboard']);
    Route::resource('users', UserController::class);
});

// Rotas por permissão
Route::middleware(['auth', 'permission:contracts.view'])->group(function () {
    Route::get('/contracts', [ContractController::class, 'index']);
});

Route::middleware(['auth', 'permission:contracts.create'])->group(function () {
    Route::get('/contracts/create', [ContractController::class, 'create']);
    Route::post('/contracts', [ContractController::class, 'store']);
});

// Múltiplas permissões (qualquer uma)
Route::middleware(['auth', 'permission:reports.view|reports.export'])->group(function () {
    Route::get('/reports', [ReportController::class, 'index']);
});

// Rotas de API com Sanctum
Route::middleware(['auth:sanctum', 'permission:api.access'])->prefix('api')->group(function () {
    Route::apiResource('contracts', Api\ContractController::class);
});
```

## Uso em Controllers

```php
<?php

namespace App\Http\Controllers;

use App\Models\Contract;
use Illuminate\Http\Request;

class ContractController extends Controller
{
    public function __construct()
    {
        // Autorização automática via Policy
        $this->authorizeResource(Contract::class, 'contract');
    }

    public function index()
    {
        // Policy: viewAny já verificada pelo authorizeResource
        $contracts = Contract::paginate();
        return view('contracts.index', compact('contracts'));
    }

    public function show(Contract $contract)
    {
        // Policy: view já verificada
        return view('contracts.show', compact('contract'));
    }

    public function approve(Contract $contract)
    {
        // Verificação manual para ação customizada
        $this->authorize('approve', $contract);
        
        $contract->update(['status' => 'approved']);
        
        return redirect()->back()->with('success', 'Contrato aprovado!');
    }

    public function massDelete(Request $request)
    {
        // Verificar permissão diretamente
        if (!auth()->user()->hasPermissionTo('contracts.delete')) {
            abort(403, 'Acesso negado');
        }

        Contract::whereIn('id', $request->ids)->delete();
        
        return response()->json(['message' => 'Contratos excluídos']);
    }
}
```

## Uso em Blade

```blade
{{-- Verificar Role --}}
@role('admin')
    <a href="/admin">Painel Admin</a>
@endrole

@hasrole('super-admin')
    <a href="/settings">Configurações</a>
@endhasrole

{{-- Verificar múltiplas roles --}}
@hasanyrole('admin|manager')
    <a href="/team">Gerenciar Equipe</a>
@endhasanyrole

{{-- Verificar Permission --}}
@can('contracts.create')
    <a href="/contracts/create" class="btn btn-primary">Novo Contrato</a>
@endcan

@cannot('contracts.delete')
    <span class="text-gray-400">Sem permissão para excluir</span>
@endcannot

{{-- Verificar Policy --}}
@can('update', $contract)
    <a href="{{ route('contracts.edit', $contract) }}">Editar</a>
@endcan

@can('approve', $contract)
    <form action="{{ route('contracts.approve', $contract) }}" method="POST">
        @csrf
        <button type="submit">Aprovar</button>
    </form>
@endcan

{{-- Menu dinâmico baseado em permissões --}}
<nav>
    @can('contracts.view')
        <a href="/contracts">Contratos</a>
    @endcan
    
    @can('payments.view')
        <a href="/payments">Pagamentos</a>
    @endcan
    
    @can('reports.view')
        <a href="/reports">Relatórios</a>
    @endcan
    
    @can('access-admin')
        <a href="/admin">Administração</a>
    @endcan
</nav>
```

## API de Gerenciamento

```php
<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\Request;
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;

class RoleController extends Controller
{
    public function index()
    {
        $roles = Role::with('permissions')->get();
        return view('admin.roles.index', compact('roles'));
    }

    public function store(Request $request)
    {
        $request->validate([
            'name' => 'required|unique:roles,name',
            'permissions' => 'array',
        ]);

        $role = Role::create(['name' => $request->name]);
        $role->syncPermissions($request->permissions ?? []);

        return redirect()->route('admin.roles.index')
            ->with('success', 'Role criada com sucesso!');
    }

    public function update(Request $request, Role $role)
    {
        $request->validate([
            'name' => 'required|unique:roles,name,' . $role->id,
            'permissions' => 'array',
        ]);

        $role->update(['name' => $request->name]);
        $role->syncPermissions($request->permissions ?? []);

        return redirect()->route('admin.roles.index')
            ->with('success', 'Role atualizada!');
    }
}

class UserRoleController extends Controller
{
    public function update(Request $request, User $user)
    {
        $request->validate([
            'roles' => 'array',
            'roles.*' => 'exists:roles,name',
        ]);

        // Sync roles (remove antigas, adiciona novas)
        $user->syncRoles($request->roles ?? []);

        return redirect()->back()->with('success', 'Roles atualizadas!');
    }

    public function addPermission(Request $request, User $user)
    {
        $request->validate([
            'permission' => 'required|exists:permissions,name',
        ]);

        // Permissão direta (além das roles)
        $user->givePermissionTo($request->permission);

        return redirect()->back()->with('success', 'Permissão adicionada!');
    }
}
```

## Auditoria de Acessos

```php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class AccessLog extends Model
{
    protected $fillable = [
        'user_id',
        'action',
        'resource',
        'resource_id',
        'ip_address',
        'user_agent',
        'granted',
        'metadata',
    ];

    protected $casts = [
        'granted' => 'boolean',
        'metadata' => 'array',
    ];

    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

// Middleware de auditoria
class AuditAccess
{
    public function handle(Request $request, Closure $next)
    {
        $response = $next($request);

        if (auth()->check()) {
            AccessLog::create([
                'user_id' => auth()->id(),
                'action' => $request->method(),
                'resource' => $request->path(),
                'ip_address' => $request->ip(),
                'user_agent' => $request->userAgent(),
                'granted' => $response->status() < 400,
            ]);
        }

        return $response;
    }
}
```

## Hierarquia Militar (SKYNET-COPAC)

```php
<?php

namespace Database\Seeders;

use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;

class MilitaryRolesSeeder extends Seeder
{
    public function run(): void
    {
        // Hierarquia: Comandante > Oficial > Suboficial > Praça
        
        $comandante = Role::create(['name' => 'comandante']);
        $oficial = Role::create(['name' => 'oficial']);
        $suboficial = Role::create(['name' => 'suboficial']);
        $praca = Role::create(['name' => 'praca']);

        // Comandante: acesso total
        $comandante->givePermissionTo(Permission::all());

        // Oficial: gerencia documentos e pessoal
        $oficial->givePermissionTo([
            'documents.view', 'documents.create', 'documents.edit', 'documents.approve',
            'personnel.view', 'personnel.edit',
            'reports.view', 'reports.export',
        ]);

        // Suboficial: operações diárias
        $suboficial->givePermissionTo([
            'documents.view', 'documents.create',
            'personnel.view',
            'reports.view',
        ]);

        // Praça: apenas visualização
        $praca->givePermissionTo([
            'documents.view',
            'personnel.view',
        ]);
    }
}
```

## Checklist de Implementação

```markdown
## Autenticação
- [ ] Login/Logout funcionando
- [ ] Registro (se aplicável)
- [ ] Reset de senha
- [ ] Email verification (se aplicável)
- [ ] Two-factor authentication (se aplicável)

## Autorização
- [ ] Roles definidas
- [ ] Permissions granulares
- [ ] Policies para cada Model
- [ ] Gates para ações globais
- [ ] Middleware nas rotas
- [ ] Verificações no Blade

## Segurança
- [ ] CSRF protection
- [ ] Rate limiting em login
- [ ] Logout em outros dispositivos
- [ ] Auditoria de acessos
- [ ] Expiração de sessão
```