跳转到主要内容
本文基于源代码(1.x 分支)整理。目前尚无官方文档,是正式发布前的包(截至 2026 年 4 月)。

什么是 Sentinel

Laravel Sentinel 是一个基于驱动、控制路由访问的安全中间件包。由 Taylor Otwell 和 Mior Muhammad Zaki 开发,支持 PHP ^8.0 / Laravel 8~13。 主要用途是保护 Telescope、Horizon、Pulse 等管理工具类路由。只要给路由挂上 SentinelMiddleware,就能用驱动定义的授权逻辑控制访问。

与传统做法的对比

Telescope 和 Horizon 各自都提供了基于 gate 的授权机制。
// 传统做法(TelescopeServiceProvider 等)
Gate::before(function ($user) {
    return $user->isAdmin() ? true : null;
});
这种方式依赖用户的认证状态,存在“不登录就无法判定”的问题。Sentinel 作为中间件运行,无论是否已认证,都可以按请求维度控制访问。同时可以在一处定义规则,应用于多个管理工具。

安装

composer require laravel/sentinel
composer.jsonextra.laravel.providers 中已经注册了 SentinelServiceProvider,服务提供者会被自动发现。也不需要额外发布配置文件。

包的架构

默认驱动(Laravel 驱动)的行为

默认的 Laravel 驱动**只在本地环境(APP_ENV=local)**才会做控制。
// src/Drivers/Laravel.php
public function authorize(Request $request): bool
{
    if (! $this->app()->environment('local')) {
        return true; // 非 local 一律放行
    }

    // 通过隧道服务访问时给出警告
    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, ...'
        );
    }

    // Docker 本地环境放行
    if ($this->isRunningOnDockerLocally($request)) {
        return true;
    }

    // 检查是否经反向代理访问
    return $this->authorizeAccessingViaReverseProxies($request);
}
流程总结如下:
Laravel 驱动在非 local 环境总是返回 true(允许)。若需要在生产环境做访问控制,请自定义驱动。

私有 IP 判定

Driver 基类的 isPrivateIp() 使用 Symfony 的 IpUtils,把以下 IP 范围视为私有 IP。
范围说明
127.0.0.0/8回环(RFC1700)
10.0.0.0/8私有(RFC1918)
192.168.0.0/16私有(RFC1918)
172.16.0.0/12私有(RFC1918)
169.254.0.0/16链路本地(RFC3927)
::1/128IPv6 回环
fc00::/7IPv6 唯一本地
fe80::/10IPv6 链路本地

Docker 本地环境检测

// 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'));
}
REMOTE_ADDR127.0.0.1,且项目根目录存在 .dockerenv 文件时,认定为 Docker 本地环境。

作为中间件使用

基本用法

use Laravel\Sentinel\Http\Middleware\SentinelMiddleware;

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

指定驱动

可以通过中间件参数传入驱动名。如果传入不存在的驱动名,会回退到默认驱动(driverOrFallback() 的行为)。
Route::middleware([SentinelMiddleware::class . ':custom-driver'])->group(function () {
    // 使用自定义驱动做授权
});

中间件实现

// 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);
}
authorize() 返回 false 时会中断并返回 HTTP 401。使用 Driver::authorizeOrFail() 时也可以抛 AuthorizationException(不过中间件本身没走这个分支)。

编写自定义驱动

继承 Driver 抽象类并实现 authorize() 方法,就能写出自定义驱动。
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
        {
            // 只允许已认证且拥有 admin 角色的用户
            $user = $request->user();

            return $user !== null && $user->hasRole('admin');
        }
    };
});
extend() 的注册可以放在 AppServiceProvider::boot() 里。

利用基类的实用方法

Driver 类里内置了 IP 判定等实用方法,自定义驱动可以直接使用。
public function authorize(Request $request): bool
{
    // 生产环境只允许来自私有 IP 的请求
    if ($this->app()->environment('production')) {
        return $this->isPrivateIp($request->ip());
    }

    // 本地只允许 Docker 或直接访问
    return $this->isRunningOnDockerLocally($request)
        || $this->authorizeAccessingViaReverseProxies($request);
}

SentinelManager 的机制

SentinelManager 继承自 Illuminate\Support\ManagerManager 是 Laravel 用来实现驱动模式的基础类,driver() 会缓存并解析驱动实例。
// 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  // 不记录日志
        );
    }
}
driverOrFallback() 在找不到指定驱动时会静默回退到默认驱动,即便你给中间件参数传入不存在的驱动名,也不会报错。 SentinelManagerSentinelServiceProvider 注册为作用域单例(scoped),因此在同一次请求中会复用驱动实例。
// src/SentinelServiceProvider.php
public function register(): void
{
    $this->app->scoped(SentinelManager::class, fn ($app) => new SentinelManager($app));
}

总结

laravel/sentinel 虽然是一个小包,但通过基于 Illuminate\Support\Manager 的驱动模式,具备很高的可扩展性。
项目内容
版本1.x
支持 PHP^8.0
支持 Laravel8~13
默认驱动仅在 local 环境做控制
自定义驱动通过 Sentinel::extend() 添加
默认的 Laravel 驱动专门用来防止本地开发时通过隧道服务的意外访问,生产环境的保护需要你自己写自定义驱动。等官方文档完善后,应该会有更具体的使用模式。

laravel/sentinel 仓库

源代码和最新变更可以在 GitHub 的 1.x 分支查看。
最后修改于 2026年7月13日