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
相关产品推荐
相关产品推荐

