> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Laravel Sentinel — indagine sul middleware di protezione delle rotte

> Lettura del codice sorgente del pacchetto laravel/sentinel. Spiega come questo middleware di sicurezza basato su driver protegga strumenti amministrativi come Telescope, Horizon e Pulse.

<Info>
  Questo articolo si basa sull'indagine del codice sorgente (branch `1.x`). Non esiste ancora documentazione ufficiale e il pacchetto è precedente al rilascio ufficiale (dato di aprile 2026).
</Info>

## Cos'è Sentinel

[Laravel Sentinel](https://github.com/laravel/sentinel) è un pacchetto di middleware di sicurezza che controlla l'accesso alle rotte tramite driver. È sviluppato da Taylor Otwell e Mior Muhammad Zaki ed è compatibile con PHP ^8.0 e Laravel da 8 a 13.

Il suo utilizzo principale è la protezione delle rotte degli strumenti di gestione come Telescope, Horizon e Pulse. Basta applicare `SentinelMiddleware` alla rotta per controllare l'accesso con la logica di autorizzazione definita dal driver.

```mermaid theme={null}
graph TD
    A["Richiesta HTTP"] --> B["SentinelMiddleware"]
    B --> C["Facade Sentinel"]
    C --> D["SentinelManager<br>(Illuminate\\Support\\Manager)"]
    D --> E["Risolve il driver<br>driverOrFallback()"]
    E --> F["Driver#authorize()"]
    F -->|true| G["Al middleware successivo"]
    F -->|false| H["abort 401"]
```

## Confronto con il metodo tradizionale

Telescope e Horizon avevano ciascuno un proprio meccanismo di autorizzazione basato su `gate`.

```php theme={null}
// Metodo tradizionale (TelescopeServiceProvider, ecc.)
Gate::before(function ($user) {
    return $user->isAdmin() ? true : null;
});
```

Questo approccio dipendeva dallo stato di autenticazione dell'utente, con il problema di "non poter decidere se non si è loggati". Sentinel funziona come middleware e controlla l'accesso a livello di richiesta, indipendentemente dall'autenticazione. Inoltre puoi definire in un unico posto regole valide per più strumenti di gestione.

## Installazione

```bash theme={null}
composer require laravel/sentinel
```

Poiché `SentinelServiceProvider` è registrato in `extra.laravel.providers` di `composer.json`, il service provider viene rilevato automaticamente. Non serve pubblicare file di configurazione aggiuntivi.

## Architettura del pacchetto

```mermaid theme={null}
classDiagram
    class Sentinel {
        +static getFacadeAccessor()
    }
    class SentinelManager {
        +createLaravelDriver() Laravel
        +getDefaultDriver() string
        +driverOrFallback(?string driver) mixed
        +extend(string driver, Closure callback) SentinelManager
    }
    class Driver {
        #Closure applicationResolver
        +authorize(Request request) bool*
        +authorizeOrFail(Request request) void
        #authorizeAccessingViaReverseProxies(Request request) bool
        #isRunningOnDockerLocally(Request request) bool
        #isPrivateIp(string requestIp) bool
        #app() Application
    }
    class Laravel {
        +authorize(Request request) bool
    }
    class SentinelMiddleware {
        +handle(Request request, Closure next, ?string driver) mixed
    }

    Sentinel --> SentinelManager : Facade
    SentinelManager --|> Manager
    Laravel --|> Driver
    SentinelMiddleware --> Sentinel : usa
```

## Comportamento del driver predefinito (driver Laravel)

Il driver predefinito `Laravel` controlla **solo nell'ambiente locale (`APP_ENV=local`)**.

```php theme={null}
// src/Drivers/Laravel.php
public function authorize(Request $request): bool
{
    if (! $this->app()->environment('local')) {
        return true; // Fuori da local consenti sempre
    }

    // Avviso su accessi tramite servizi di tunnel
    if ($this->isPrivateIp($request->ip())
        && ! $request->isFromTrustedProxy()
        && Str::endsWith($request->host(), ['.sharedwithexpose.com', '.ngrok-free.app', '.ngrok.io'])) {
        throw new RuntimeException(
            'Unable to access "..." using "local" environment, ...'
        );
    }

    // Consenti l'ambiente Docker locale
    if ($this->isRunningOnDockerLocally($request)) {
        return true;
    }

    // Verifica gli accessi tramite reverse proxy
    return $this->authorizeAccessingViaReverseProxies($request);
}
```

Il flusso può essere riassunto così.

```mermaid theme={null}
flowchart TD
    A[Richiesta ricevuta] --> B{Ambiente local?}
    B -->|No| C[Restituisci true<br>(sempre consentito)]
    B -->|Sì| D{IP privato e<br>fuori trustedProxy e<br>servizio di tunnel?}
    D -->|Sì| E[Solleva RuntimeException<br>Mostra istruzioni]
    D -->|No| F{Ambiente Docker locale?<br>127.0.0.1 + .dockerenv}
    F -->|Sì| G[Restituisci true<br>(consentito)]
    F -->|No| H{IP non privato<br>via trustedProxy?}
    H -->|Sì| I[Restituisci false<br>(bloccato)]
    H -->|No| J[Restituisci true<br>(consentito)]
```

<Warning>
  Il driver `Laravel` restituisce sempre `true` (consentito) al di fuori dell'ambiente `local`. Se ti serve un controllo degli accessi in produzione, crea un driver personalizzato.
</Warning>

### Determinazione dell'IP privato

`isPrivateIp()` nella classe base `Driver` usa `IpUtils` di Symfony e considera privati i seguenti range di IP.

| Range            | Descrizione          |
| ---------------- | -------------------- |
| `127.0.0.0/8`    | Loopback (RFC1700)   |
| `10.0.0.0/8`     | Privato (RFC1918)    |
| `192.168.0.0/16` | Privato (RFC1918)    |
| `172.16.0.0/12`  | Privato (RFC1918)    |
| `169.254.0.0/16` | Link-local (RFC3927) |
| `::1/128`        | Loopback IPv6        |
| `fc00::/7`       | Unique local IPv6    |
| `fe80::/10`      | Link-local IPv6      |

### Rilevamento di ambiente Docker locale

```php theme={null}
// src/Drivers/Driver.php
protected function isRunningOnDockerLocally(Request $request): bool
{
    return $request->server->get('REMOTE_ADDR') === '127.0.0.1'
        && file_exists(base_path('.dockerenv'));
}
```

Considera come ambiente Docker locale il caso in cui `REMOTE_ADDR` è `127.0.0.1` ed esiste il file `.dockerenv` nella root del progetto.

## Uso come middleware

### Uso di base

```php theme={null}
use Laravel\Sentinel\Http\Middleware\SentinelMiddleware;

Route::middleware(SentinelMiddleware::class)->group(function () {
    Route::get('/telescope', function () { /* ... */ });
    Route::get('/horizon', function () { /* ... */ });
    Route::get('/pulse', function () { /* ... */ });
});
```

### Specificare un driver

Puoi passare al middleware il nome di un driver come argomento. Se passi un nome di driver inesistente, si ricade sul driver predefinito (comportamento di `driverOrFallback()`).

```php theme={null}
Route::middleware([SentinelMiddleware::class . ':custom-driver'])->group(function () {
    // Autorizzazione con driver personalizzato
});
```

### Implementazione del middleware

```php theme={null}
// src/Http/Middleware/SentinelMiddleware.php
public function handle(Request $request, Closure $next, ?string $driver = null)
{
    abort_unless(Sentinel::driverOrFallback($driver)->authorize($request), 401);

    return $next($request);
}
```

Se `authorize()` restituisce `false`, il middleware interrompe con HTTP 401. Con `Driver::authorizeOrFail()` puoi anche lanciare `AuthorizationException` (il middleware in sé non lo usa).

## Creazione di un driver personalizzato

Puoi creare un driver personalizzato estendendo la classe astratta `Driver` e implementando `authorize()`.

```php theme={null}
use Laravel\Sentinel\Sentinel;
use Laravel\Sentinel\Drivers\Driver;
use Illuminate\Http\Request;

Sentinel::extend('admin-only', function ($app) {
    return new class extends Driver {
        public function authorize(Request $request): bool
        {
            // Consente solo utenti autenticati con ruolo admin
            $user = $request->user();

            return $user !== null && $user->hasRole('admin');
        }
    };
});
```

La registrazione con `extend()` va fatta in `AppServiceProvider::boot()` o simili.

### Sfruttare i metodi utility della classe base

La classe `Driver` mette a disposizione utili metodi per la determinazione dell'IP, che puoi usare liberamente dai driver personalizzati.

```php theme={null}
public function authorize(Request $request): bool
{
    // In produzione consenti solo da IP privati
    if ($this->app()->environment('production')) {
        return $this->isPrivateIp($request->ip());
    }

    // In locale solo Docker o accesso diretto
    return $this->isRunningOnDockerLocally($request)
        || $this->authorizeAccessingViaReverseProxies($request);
}
```

## Come funziona SentinelManager

`SentinelManager` estende `Illuminate\Support\Manager`. `Manager` è la classe base di Laravel per implementare il pattern driver e risolve le istanze del driver mantenendole in cache tramite `driver()`.

```php theme={null}
// src/SentinelManager.php
class SentinelManager extends Manager
{
    protected function createLaravelDriver()
    {
        return new Laravel(fn () => $this->getContainer());
    }

    public function getDefaultDriver()
    {
        return 'laravel';
    }

    public function driverOrFallback(?string $driver)
    {
        return rescue(
            fn () => $this->driver($driver),
            value(fn () => $this->driver()),
            false  // Non registrare nel log
        );
    }
}
```

`driverOrFallback()` ricade silenziosamente sul driver predefinito anche se il driver specificato non è trovato, per cui non genera errori se al middleware passi un nome di driver inesistente.

`SentinelManager` viene registrato come singleton con scope (`scoped`) dal `SentinelServiceProvider`, quindi l'istanza del driver viene riutilizzata all'interno di una singola richiesta.

```php theme={null}
// src/SentinelServiceProvider.php
public function register(): void
{
    $this->app->scoped(SentinelManager::class, fn ($app) => new SentinelManager($app));
}
```

## Conclusioni

`laravel/sentinel` è un pacchetto piccolo ma, grazie al pattern driver basato su `Illuminate\Support\Manager`, ha un'alta estendibilità.

| Elemento              | Contenuto                             |
| --------------------- | ------------------------------------- |
| Versione              | 1.x                                   |
| PHP supportato        | ^8.0                                  |
| Laravel supportato    | 8-13                                  |
| Driver predefinito    | Controllo solo nell'ambiente local    |
| Driver personalizzati | Aggiungibili con `Sentinel::extend()` |

Il driver predefinito `Laravel` è specializzato nell'evitare gli accessi tramite servizi di tunnel durante lo sviluppo locale; per la protezione in produzione devi creare un driver personalizzato. Quando la documentazione ufficiale sarà pronta, emergeranno pattern d'uso più concreti.

<Card title="Repository laravel/sentinel" icon="github" href="https://github.com/laravel/sentinel">
  Codice sorgente e ultime modifiche sono nel branch `1.x` di GitHub.
</Card>


## Related topics

- [FAQ sulla nuova struttura dell'app da Laravel 11](/it/advanced/app-structure-faq.md)
- [Middleware](/it/middleware.md)
- [Laravel Passkeys — indagine iniziale (passkeys-server + @laravel/passkeys)](/it/blog/passkeys-introduction.md)
- [Aggiornamenti Laravel di marzo 2026](/it/blog/changelog/202603.md)
- [Rotte](/it/packages/laravel-bluesky/route.md)
