Laravel Passport自定义Guard保护API返回HTML而非JSON问题求助
Laravel自定义Admin Guard保护API接口返回302跳转HTML问题
问题场景
Laravel项目中已实现管理员独立登录功能,基于自定义Guard与中间件,原本运行正常。引入Laravel Passport保护API路由后出现异常:
- 普通用户API接口使用
auth:api中间件可正常工作 - 管理员API接口通过自定义
auth.admin中间件保护时,返回302状态码,响应内容为HTML(控制台可见但前端无输出) - 移除路由保护后,管理员接口恢复正常
相关代码
AdminMiddleware
<?php namespace App\Http\Middleware; use Closure; use Illuminate\Support\Facades\Auth; use Illuminate\Http\Request; class AdminMiddleware { public function handle($request, Closure $next, $guard = null) { if (Auth::guard('admin')->check()) { return $next($request); } else { return redirect()->route('admin.login'); } } }
Kernel.php
protected $routeMiddleware = [ 'auth.admin' => \App\Http\Middleware\AdminMiddleware::class, 'auth' => \App\Http\Middleware\Authenticate::class, ];
config/auth.php
'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], 'api' => [ 'driver' => 'passport', 'provider' => 'users', 'hash' => false, ], 'admin' => [ 'driver' => 'session', 'provider' => 'admins', ], 'adminApi' => [ 'driver' => 'passport', 'provider' => 'admins', 'hash' => false, ] ],
routes/api.php
Route::group(['middleware' => ['auth.admin:adminApi']], function(){ Route::get('/fetch-announcements', [AnnouncementController::class, 'showAnnouncement']); Route::post('/store-announcements',[AnnouncementController::class, 'storeAnnouncement']); });
Models/Admin.php
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Laravel\Sanctum\HasApiTokens; class Admin extends Authenticatable { use HasFactory, HasApiTokens; protected $fillable =[ 'email', ]; protected $hidden = [ 'password', 'remember_token', ]; protected $casts = [ 'email_verified_at' => 'datetime', ]; }
前端请求代码
await axios.get('/api/fetch-announcements', { headers: { 'Accept': 'application/json' } }) .then(response => { this.announcements = response.data console.log(this.announcements) }) .catch(err => console.error(err))
问题原因
- 中间件逻辑不适配API请求:当前
AdminMiddleware在未认证时返回页面跳转(302),但API请求需要JSON格式的401未授权响应,跳转导致返回登录页面的HTML内容。 - Guard参数未被正确使用:路由中传入了
adminApi(Passport驱动的Guard),但中间件硬编码使用admin(Session驱动的Guard),导致认证逻辑错误。 - Admin模型依赖错误:模型中引入的是Sanctum的
HasApiTokens,而非Passport对应的Trait,无法正确支持Passport令牌认证。
解决方案
1. 修正AdminMiddleware逻辑
修改中间件,支持API请求的JSON响应,并正确使用传入的Guard参数:
<?php namespace App\Http\Middleware; use Closure; use Illuminate\Support\Facades\Auth; use Illuminate\Http\Request; class AdminMiddleware { public function handle($request, Closure $next, $guard = 'admin') { // 使用路由传入的Guard进行认证检查 if (Auth::guard($guard)->check()) { return $next($request); } // 针对API请求返回JSON错误 if ($request->expectsJson()) { return response()->json(['message' => '未授权访问'], 401); } // web端仍跳转登录页 return redirect()->route('admin.login'); } }
2. 替换Admin模型的API Token Trait
将Sanctum的HasApiTokens替换为Passport的版本:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Laravel\Passport\HasApiTokens; // 替换为Passport的Trait class Admin extends Authenticatable { use HasFactory, HasApiTokens, Notifiable; protected $fillable =[ 'email', ]; protected $hidden = [ 'password', 'remember_token', 'api_token', ]; protected $casts = [ 'email_verified_at' => 'datetime', ]; }
3. 确保Passport正确配置
- 执行Passport安装命令,生成必要的加密密钥和客户端:
php artisan passport:install
- 在
App\Providers\AuthServiceProvider的boot方法中注册Passport路由:
use Laravel\Passport\Passport; public function boot() { $this->registerPolicies(); Passport::routes(); // 可根据需求设置令牌过期时间等参数 }
4. 验证API请求携带正确令牌
确保前端请求时在Header中携带Passport颁发的Bearer令牌:
await axios.get('/api/fetch-announcements', { headers: { 'Accept': 'application/json', 'Authorization': 'Bearer ' + yourAdminToken } }) .then(response => { this.announcements = response.data console.log(this.announcements) }) .catch(err => console.error(err))
内容的提问来源于stack exchange,提问作者PMConcepcion
相关产品推荐
相关产品推荐

