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

Laravel中间件中CookProcess创建权限校验失效问题求助

Laravel路由权限中间件返回403问题排查

问题现象

配置带auth中间件的路由组后,其中POST路由/products/{product}/cookProcessCreate添加can:create,cookProcess权限中间件时,请求返回403状态码,且CookProcessPolicy的create方法未触发日志输出;但在控制器store方法中使用$this->authorize('create',CookProcess::class)时授权正常,其他路由的权限校验也能正常触发Policy日志。

路由代码

Route::middleware('auth')->group(function (){
    //resource controller for products
    Route::apiResource("products",ProductController::class);
    //additional routes for cook processes
    Route::prefix("products")->group(function (){
        Route::get("{product}/{cookProcess}",[CookProcessController::class,"show"]);
        // 存在问题的路由
        Route::post("/{product}/cookProcessCreate",[CookProcessController::class,"store"])->middleware('can:create,cookProcess');
        Route::delete("{product}/{cookProcess}",[CookProcessController::class,"destroy"])->middleware('can:delete,cookProcess');
        Route::patch("{product}/{cookProcess}",[CookProcessController::class,"update"])->middleware('can:update,cookProcess');
    });
});

CookProcessPolicy代码

<?php

namespace App\Policies;

use App\Models\CookProcess;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;

class CookProcessPolicy
{
    /**
     * Determine whether the user can view the model.
     */
    public function view(User $user, CookProcess $cookProcess): bool
    {
        Log::debug("process policyview launched");
        return Auth::check();
    }

    /**
     * Determine whether the user can create models.
     */
    public function create(User $user): bool
    {
        Log::debug("process policy create launched");
        return Auth::check();
    }

    /**
     * Determine whether the user can update the model.
     */
    public function update(User $user, CookProcess $cookProcess): bool
    {
        Log::debug("process policyupdate launched");
        return $user->hasPermissionTo('edit notes');
    }

    /**
     * Determine whether the user can delete the model.
     */
    public function delete(User $user, CookProcess $cookProcess): bool
    {
        Log::debug("process policydelete launched");
        return $user->hasPermissionTo('delete notes');
    }

    // 其他未实现方法省略
}

控制器代码

<?php

namespace App\Http\Controllers;

use App\Models\CookProcess;
use App\Models\Product;
use Illuminate\Http\Request;

class CookProcessController extends Controller
{
    public function store(Request $request)
    {
        //$this->authorize('create',CookProcess::class);
        $validData = $request->validate([
            "name"=>"string|required|unique:products|",
            'product_id'=>"integer|exists:products,id",
            "duration"=>"required|numeric",
            "cookPresenceInterval"=>"required|numeric",
            "description"=>"required|string|min:20"
        ]);
        $newCookProcess = CookProcess::create($validData);
        return response()->json(['message'=>"Cook process created successfully id - $newCookProcess"]);
    }

    public function show(Product $product,CookProcess $cookProcess)
    {
        return response()->json(["cookProcess"=>$cookProcess]);
    }

    public function update(Request $request,Product $product, CookProcess $cookProcess)
    {
        $cookProcess->update($request->all());
        return response()->json(['message'=>'Cook process updated successfully']);
    }

    public function destroy(CookProcess $cookProcess)
    {
        $cookProcess->delete();
        return response()->json(['message'=>'Cook process has been deleted']);
    }
}

测试代码

public function testCookProcessCreation()
{
    $this->seed(PermissionsTableSeeder::class);
    $this->seed(RolesTableSeeder::class);
    $user=User::factory()->create();
    $user->assignRole('site_user');
    $this->actingAs($user);
    $product=Product::factory()->create();
    $processData = [
        "name"=>'testname',
        "duration"=>fake()->numberBetween(1,10),
        "cookPresenceInterval"=>fake()->numberBetween(0,5),
        "description"=>fake()->text(50),
        "product_id"=>$product->id
    ];
    $response=$this->post("/api/products/" . $product->id . '/cookProcessCreate',$processData);
    $response->assertStatus(200);
    $createdProcess = CookProcess::where('name','testname')->first();
    $this->assertNotNull($createdProcess);
}

问题原因

路由中间件can:create,cookProcess中的cookProcess被Laravel识别为路由参数,框架会尝试从当前路由中获取该参数并解析为CookProcess模型实例,但该POST路由仅包含product参数,不存在cookProcess参数,导致模型解析失败,直接返回403,且不会触发Policy中不需要模型实例的create方法。

而控制器中使用$this->authorize('create',CookProcess::class)时,明确传递了CookProcess类名,Laravel会正确调用Policy的create(User $user)方法,因此授权正常。

解决方案

修改路由中间件,明确传递CookProcess类名而非路由参数:

// 先在路由文件顶部导入CookProcess类
use App\Models\CookProcess;

// 修改问题路由的中间件
Route::post("/{product}/cookProcessCreate",[CookProcessController::class,"store"])
    ->middleware('can:create,' . CookProcess::class);

或者直接写类的完整命名空间:

Route::post("/{product}/cookProcessCreate",[CookProcessController::class,"store"])
    ->middleware('can:create,App\Models\CookProcess');

这样Laravel会正确识别需要调用Policy的create方法(无模型参数的版本),授权逻辑正常执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 12:35:57