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

Laravel 9 API路由auth:api中间件跳转异常求助

问题描述

我安装了Laravel Breeze实现认证,登录注册表单可正常访问(http://localhost:8000/login)。但登录后访问受auth:api中间件保护的/api/categories路由时,会被重定向到首页;移除中间件后,路由可正常访问但无需登录验证。

可正常运行的路由代码

Route::controller(App\Http\Controllers\API\CategoryController::class)->group(function(){
    Route::get('categories', 'index')->name('categories.index');
});

无法正常运行的路由代码

Route::group(['middleware' => 'auth:api'], function(){
    Route::controller(App\Http\Controllers\API\CategoryController::class)->group(function(){
        Route::get('categories', 'index')->name('categories.index');
    });
});

CategoryController代码

<?php

namespace App\Http\Controllers\API;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\Category;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;

class CategoryController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $cat = $this->getCategories();
        return response()->json($cat);
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        $cat = $this->getCategories();
        return view('create-category',compact('cat'));
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        return Auth::user();
        $category = Category::firstOrCreate(
            ['name' => $role_name],
            ['guard_name' => 'api']
        );
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        $cat = $this->getCategories($id);
//        $cat = Category::where('id', $id)->get()->keyBy('id');
        return response()->json($cat);
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        //
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        //
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        //
    }

    public function getParentCategory($id) {
        $cat = Category::where('id', $id)->get()->keyBy('id');
        return $cat;
    }

    public function getChildCategory($id, $keyBy = null) {
//        return $keyBy;
        $cat = Category::where('parent_id', $id)->get()->keyBy('id');
        return $cat;
    }

    private function setKeyBy($collection, $name) {
        $collection = $collection->keyBy($name);
        return $collection;
    }

    public function getCategories($category_id = null) {
        $cat = Category::where('id', '>', 0);
        if(!is_null($category_id)) {
            $cat = $cat->where('id', $category_id)->get()->keyBy('id');
        } else {
            $cat = $cat->whereNull('parent_id')->get()->keyBy('id');

            foreach($cat as $catID=>$catArray) {
                $subCat = $this->getChildCategory($catID, 'id');
//                $subCat = $subCat->keyBy('id');
                if ($subCat->first()) {
                    $cat[$catID]['subcat'] = $subCat;
                }
            }
        }
        return $cat;
    }

    public function createCategoryForm() {
        $cat = $this->getCategories();
        return view('create-category',compact('cat'));
    }

    public function categoryDropown($child_id = null) {
        $cat = $this->getCategories();
    }

    public function categoryChildDropown($child_id) {
        $cat = Category::where('parent_id', $child_id)->get();
        return $cat;
    }
}

解决方案

问题核心是auth:api和Breeze默认的Web认证分属不同体系:Breeze用web guard基于会话认证,而auth:api默认用Token认证,两者状态不互通,所以Web登录后API guard仍识别不到用户。

方法一:改用auth:web中间件(适合前后端同构场景)

如果API是给项目内前端页面调用的,直接替换中间件,让Web会话的登录状态生效:

Route::group(['middleware' => 'auth:web'], function(){
    Route::controller(App\Http\Controllers\API\CategoryController::class)->group(function(){
        Route::get('categories', 'index')->name('categories.index');
    });
});

方法二:配置API Token认证(纯API场景)

如果是给第三方客户端提供API,需要实现Token认证:

  1. 给users表添加api_token字段,创建迁移文件:
Schema::table('users', function (Blueprint $table) {
    $table->string('api_token', 80)->unique()->nullable()->default(null);
});
  1. 运行迁移:php artisan migrate
  2. 登录时给用户生成/返回api_token,可在Breeze登录控制器中补充逻辑
  3. 调用API时,在请求头携带Authorization: Bearer {你的api_token},或在URL后拼接?api_token={你的api_token}

另外,Laravel 8+推荐使用Sanctum做API认证,它支持Token和SPA认证,适配更现代的API场景,可按需安装配置。


内容的提问来源于stack exchange,提问作者mathius1

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 20:15:16