Laravel 5 中间件“所有者”?

Posted

技术标签:

【中文标题】Laravel 5 中间件“所有者”?【英文标题】:Laravel 5 Middleware "Owner"? 【发布时间】:2015-06-26 08:12:04 【问题描述】:

我在创建“所有者”中间件时遇到了问题。

例如,我有一个与user_id 键关联的ArticlesUsermodel。

我想将“所有者”中间件添加到ArticlesController,以便该文章的唯一所有者可以编辑、更新和删除它。

我一直在寻找这个问题一段时间,但从未找到可以工作的代码。 他们中的一些人试图让它与表单请求一起工作,但我对使用中间件很感兴趣。

【问题讨论】:

【参考方案1】:
    创建中间件:
php artisan make:middleware OwnerMiddleware
namespace App\Http\Middleware;

use App\Article;
use Closure;
use Illuminate\Contracts\Auth\Guard;

class OwnerMiddleware

    /**
     * The Guard implementation.
     *
     * @var Guard
     */
    protected $auth;

    /**
     * Create a new filter instance.
     *
     * @param  Guard  $auth
     * @return void
     */
    public function __construct(Guard $auth)
    
        $this->auth = $auth;
    

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    
        $articleId = $request->segments()[1];
        $article = Article::findOrFail($articleId);

        if ($article->user_id !== $this->auth->getUser()->id) 
            abort(403, 'Unauthorized action.');
        

        return $next($request);
    

    添加到app\Http\Kernel.php:
protected $routeMiddleware = [
    'owner' => 'App\Http\Middleware\OwnerMiddleware',
];
    在路由中使用中间件:
Route::group(['middleware' => ['owner']], function() 
    // your route
);

【讨论】:

是否必须为每个模型创建一个新的handle() 这看起来不错,但它取决于 URL 结构,不是吗?有什么方法可以在 $request 中获取模型并比较 user_id?【参考方案2】:

您也可以使用 route 和middleware parameters,它有一些优点:

即使请求结构发生变化,您的中间件仍然可以工作 中间件可重复用于不同的资源 您可以在控制器中使用它

这是中间件 (app/Http/Middleware/AbortIfNotOwner.php):

<?php

namespace App\Http\Middleware;

use Closure;

class AbortIfNotOwner

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  string    $resourceName
     * @return mixed
     */
    public function handle($request, Closure $next, $resourceName)
    
        $resourceId = $request->route()->parameter($resourceName);

        $user_id = \DB::table($resourceName)->find($resourceId)->user_id;

        if ($request->user()->id != $user_id) 
            abort(403, 'Unauthorized action.');
        

        return $next($request);
    

内部app\Http\Kernel.php

protected $routeMiddleware = [
     'owner' => 'App\Http\Middleware\AbortIfNotOwner',
];

在您的路线文件中 (app/Http/routes.php):

Route::group(['middleware' => ['owner:articles']], function() 
    // your route
);

并且可以选择在控制器中调用它:

public function __construct()

    $this->middleware('owner:articles', ['only' => ['edit', 'update']]);

【讨论】:

非常聪明!这应该是 laravel 中的默认值 问题是它最终查询了两次,你可能会更好地在模型绑定之后实现它,或者在更新方法中的模型上实现它。 什么意思? constructroutes 方法是互补的,你不需要同时做这两个。 您在每次 Web 请求时都从数据库中获取所有者,从而使用此中间件产生不必要的 n+1 错误。从请求对象中获取经过身份验证的用户,中间件已经在传递这些数据,不需要为每个该死的请求额外点击一次数据库。 “从请求对象中获取经过身份验证的用户”。这不正是我所做的吗?:$request-&gt;user()-&gt;id.

以上是关于Laravel 5 中间件“所有者”?的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 在中间件中获取 id 获取参数

带有角度路由的 Laravel 5 中间件

监控系统实践第13天:5天上手Laravel8.5之中间件篇(2/5)

如何在 laravel 5.5 中使用 phpunit 测试中间件?

Laravel 5.6 中的“绑定”中间件有啥作用?

Laravel 5.3 中间件:创建用于身份验证的中间件