在 Laravel 中实现多守卫 JWT 权限校验时,必须通过构造函数注入指定命名的 Guard 实例(如 $adminGuard),依赖容器自动解析 auth.driver.admin 服务,配合 auth:admin 中间件完成用户认证,确保类型安全与可测试性。

在 Laravel 中实现多守卫 JWT 权限校验时,构造函数注入的核心是**明确指定 guard 实例**,而非依赖默认守卫。直接 `Auth::guard()` 是静态调用,无法被容器自动解析;而通过构造函数注入 `Guard` 实例,才能保障类型安全、可测试性,并与服务容器生命周期一致。
注入指定守卫的 Guard 实例
每个守卫(如 api、admin、merchant)对应一个绑定到容器的命名实例。Laravel 的 `AuthManager` 会为每个 guard 名生成对应的 `Illuminate\Auth\Guard` 或其 JWT 实现(如 `Tymon\JWTAuth\JWTGuard`)。
- 在控制器或服务类构造函数中,使用类型提示 + 守卫名前缀注入:
app/Http/Controllers/AdminController.php
use Illuminate\Contracts\Auth\Guard;
use Tymon\JWTAuth\JWTGuard;
class AdminController extends Controller
{
protected $adminGuard;
public function __construct(Guard $adminGuard)
{
// 注意:$adminGuard 实际是绑定名为 'admin' 的 guard 实例
// Laravel 自动将参数名 'adminGuard' 映射为 'auth.driver.admin' 服务
$this->adminGuard = $adminGuard;
}
public function index()
{
$user = $this->adminGuard->user(); // 获取当前 admin 用户
if (!$user) {
return response(['error' => 'Unauthorized'], 401);
}
return response($user);
}
}
- 该写法依赖 Laravel 的容器参数解析规则:当构造函数参数名为
$xxxGuard,且存在同名 guard(如 config/auth.php 中定义了'guards' => ['admin' => [...]]),容器会自动绑定auth.driver.admin服务到该参数。 - 若命名不匹配(如参数叫
$guard),则注入的是默认守卫(api或web),极易出错。
配合中间件确保请求上下文正确
构造函数注入只解决“获取守卫实例”的问题,但守卫是否已从请求中解析出用户,取决于中间件是否已执行。
- 必须在路由中显式指定守卫名的中间件,例如:
middleware('auth:admin'),不能只写auth:api或auth - 该中间件会调用
Auth::guard('admin')->authenticate(),完成 token 解析、payload 验证、用户加载,并将结果缓存到当前请求周期 - 因此,构造函数注入的
$adminGuard在index()中调用user()才能拿到有效用户对象;否则返回 null
自定义服务类中的注入写法
若需在非控制器类(如 Service、Repository)中使用特定守卫,推荐通过接口契约 + 绑定方式增强解耦:
- 定义接口(可选,提升可测性):
interface AdminAuthGuard
{
public function user();
public function check();
}
- 在
AppServiceProvider中绑定:
app/Providers/AppServiceProvider.php
use Illuminate\Support\Facades\Auth;
use Illuminate\Contracts\Auth\Guard;
public function register()
{
$this->app->when(AdminService::class)
->needs(Guard::class)
->give(function () {
return Auth::guard('admin'); // 返回具体实例,非静态代理
});
}
- 然后在服务类中直接注入:
class AdminService
{
public function __construct(protected Guard $guard) {}
public function doSomething()
{
$admin = $this->guard->user();
// ...
}
}
避免常见错误
-
不要在构造函数里调用
Auth::guard('admin')静态方法——这绕过容器,导致无法 mock 测试,且无法享受自动解析和绑定优势 -
不要注入
AuthManager或AuthFacade 后再手动取 guard——破坏依赖注入原则,增加耦合 - 确保 config/auth.php 中已正确定义该守卫及其 provider,否则容器无法解析对应服务
-
JWT 模型必须实现
JWTSubject接口,否则user()返回空或抛异常


















