You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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))

问题原因

  1. 中间件逻辑不适配API请求:当前AdminMiddleware在未认证时返回页面跳转(302),但API请求需要JSON格式的401未授权响应,跳转导致返回登录页面的HTML内容。
  2. Guard参数未被正确使用:路由中传入了adminApi(Passport驱动的Guard),但中间件硬编码使用admin(Session驱动的Guard),导致认证逻辑错误。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 18:40:39