> ## 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 — analyse du middleware de protection des routes

> Analyse du code source du package laravel/sentinel. Découvrez comment ce middleware de sécurité basé sur des drivers protège les outils d'administration tels que Telescope, Horizon et Pulse.

<Info>
  Cet article s'appuie sur une analyse du code source (branche `1.x`). Aucune documentation officielle n'existe encore et le package est en pré-release (à la date d'avril 2026).
</Info>

## Qu'est-ce que Sentinel ?

[Laravel Sentinel](https://github.com/laravel/sentinel) est un package de middleware de sécurité qui contrôle l'accès aux routes via un pattern de drivers. Développé par Taylor Otwell et Mior Muhammad Zaki, il est compatible PHP ^8.0 et Laravel 8 à 13.

Son usage principal est la protection des routes d'outils d'administration comme Telescope, Horizon ou Pulse. Il suffit d'appliquer `SentinelMiddleware` à une route pour contrôler l'accès selon la logique d'autorisation définie par le driver.

```mermaid theme={null}
graph TD
    A["Requête HTTP"] --> B["SentinelMiddleware"]
    B --> C["Facade Sentinel"]
    C --> D["SentinelManager<br>(Illuminate\\Support\\Manager)"]
    D --> E["Résolution du driver<br>driverOrFallback()"]
    E --> F["Driver#authorize()"]
    F -->|true| G["Middleware suivant"]
    F -->|false| H["abort 401"]
```

## Comparaison avec l'approche classique

Telescope et Horizon disposent chacun d'un mécanisme d'autorisation basé sur des `gate`.

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

Ce mécanisme dépend de l'état d'authentification et pose problème quand « on n'est pas connecté, donc on ne peut pas décider ». En tant que middleware, Sentinel contrôle l'accès par requête, indépendamment de l'authentification. Il permet aussi de définir les règles en un seul endroit pour plusieurs outils d'administration.

## Installation

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

`SentinelServiceProvider` est déclaré dans `extra.laravel.providers` du `composer.json`, il est donc détecté automatiquement. Aucun fichier de configuration à publier.

## Architecture du package

```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 : utilise
```

## Fonctionnement du driver par défaut (driver Laravel)

Le driver par défaut `Laravel` **ne contrôle l'accès qu'en environnement local (`APP_ENV=local`)**.

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

    // Avertissement pour les accès via un service de tunneling
    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, ...'
        );
    }

    // Autorise l'environnement Docker local
    if ($this->isRunningOnDockerLocally($request)) {
        return true;
    }

    // Vérifie l'accès via reverse proxy
    return $this->authorizeAccessingViaReverseProxies($request);
}
```

Résumé du flux :

```mermaid theme={null}
flowchart TD
    A[Requête reçue] --> B{Env. local ?}
    B -->|No| C[Retourne true<br>(toujours autorisé)]
    B -->|Yes| D{IP privée ET<br>hors trustedProxy ET<br>service de tunneling ?}
    D -->|Yes| E[Lève une RuntimeException<br>affiche l'aide de config]
    D -->|No| F{Docker local ?<br>127.0.0.1 + .dockerenv}
    F -->|Yes| G[Retourne true<br>(autorisé)]
    F -->|No| H{IP non privée ET<br>via trustedProxy ?}
    H -->|Yes| I[Retourne false<br>(bloqué)]
    H -->|No| J[Retourne true<br>(autorisé)]
```

<Warning>
  Le driver `Laravel` retourne toujours `true` (autorisé) en dehors de l'environnement `local`. Pour un contrôle d'accès en production, créez un driver personnalisé.
</Warning>

### Détection d'IP privée

La méthode `isPrivateIp()` de la classe de base `Driver` utilise `IpUtils` de Symfony pour identifier les IP dans les plages suivantes comme privées.

| Plage            | Description          |
| ---------------- | -------------------- |
| `127.0.0.0/8`    | Loopback (RFC1700)   |
| `10.0.0.0/8`     | Privée (RFC1918)     |
| `192.168.0.0/16` | Privée (RFC1918)     |
| `172.16.0.0/12`  | Privée (RFC1918)     |
| `169.254.0.0/16` | Link-local (RFC3927) |
| `::1/128`        | Loopback IPv6        |
| `fc00::/7`       | Unique-local IPv6    |
| `fe80::/10`      | Link-local IPv6      |

### Détection d'environnement Docker local

```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'));
}
```

Considère l'environnement comme Docker local si `REMOTE_ADDR` vaut `127.0.0.1` et qu'un fichier `.dockerenv` existe à la racine du projet.

## Utilisation comme middleware

### Utilisation de 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 () { /* ... */ });
});
```

### Spécifier un driver

Passez le nom du driver en argument du middleware. Si le driver n'existe pas, un fallback vers le driver par défaut est effectué (comportement de `driverOrFallback()`).

```php theme={null}
Route::middleware([SentinelMiddleware::class . ':custom-driver'])->group(function () {
    // Autorisation via le driver personnalisé
});
```

### Implémentation du 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);
}
```

Si `authorize()` retourne `false`, la requête est interrompue avec un HTTP 401. `Driver::authorizeOrFail()` permet également de lever une `AuthorizationException` (non utilisée par le middleware lui-même).

## Créer un driver personnalisé

Étendez la classe abstraite `Driver` et implémentez la méthode `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
        {
            // Autoriser uniquement les utilisateurs authentifiés avec le rôle admin
            $user = $request->user();

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

Enregistrez le driver dans `AppServiceProvider::boot()` ou équivalent.

### Utiliser les méthodes utilitaires de la classe de base

La classe `Driver` propose des méthodes utiles (détection d'IP, etc.) réutilisables librement.

```php theme={null}
public function authorize(Request $request): bool
{
    // En production, autoriser uniquement les IP privées
    if ($this->app()->environment('production')) {
        return $this->isPrivateIp($request->ip());
    }

    // En local, uniquement Docker ou accès direct
    return $this->isRunningOnDockerLocally($request)
        || $this->authorizeAccessingViaReverseProxies($request);
}
```

## Fonctionnement de SentinelManager

`SentinelManager` étend `Illuminate\Support\Manager`. `Manager` est la classe de base Laravel qui implémente le pattern de drivers en résolvant l'instance via `driver()` avec mise en cache.

```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  // Ne pas journaliser
        );
    }
}
```

`driverOrFallback()` retombe silencieusement sur le driver par défaut si le driver spécifié n'est pas trouvé, ce qui permet de passer sans erreur un nom de driver inexistant en argument du middleware.

`SentinelManager` est enregistré en singleton scopé (`scoped`) par `SentinelServiceProvider` : l'instance du driver est réutilisée durant une requête.

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

## Conclusion

`laravel/sentinel` est un petit package, mais son utilisation de `Illuminate\Support\Manager` lui confère une bonne extensibilité.

| Élément                | Contenu                                    |
| ---------------------- | ------------------------------------------ |
| Version                | 1.x                                        |
| PHP pris en charge     | ^8.0                                       |
| Laravel pris en charge | 8 à 13                                     |
| Driver par défaut      | Contrôle uniquement en environnement local |
| Driver personnalisé    | Ajoutable via `Sentinel::extend()`         |

Le driver par défaut `Laravel` est spécialisé dans la prévention des accès via un service de tunneling en développement local ; pour protéger la production, il faut écrire un driver personnalisé. La documentation officielle, à venir, précisera les patrons d'utilisation.

<Card title="Dépôt laravel/sentinel" icon="github" href="https://github.com/laravel/sentinel">
  Retrouvez le code source et les changements récents sur la branche `1.x` du dépôt GitHub.
</Card>


## Related topics

- [Protection CSRF](/fr/csrf.md)
- [Middleware](/fr/middleware.md)
- [Routage](/fr/routing.md)
- [Laravel et le développement IA](/fr/ai.md)
- [Structure des répertoires](/fr/directory-structure.md)
