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

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

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

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

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

【问题讨论】:

    标签: php laravel permissions laravel-5 middleware


    【解决方案1】:
    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);
        }
    }
    
    1. 添加到app\Http\Kernel.php:
    protected $routeMiddleware = [
        'owner' => 'App\Http\Middleware\OwnerMiddleware',
    ];
    
    1. 在路由中使用中间件:
    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.
    猜你喜欢
    • 2015-08-29
    • 1970-01-01
    • 1970-01-01
    • 2015-06-18
    • 1970-01-01
    • 2015-05-23
    • 1970-01-01
    • 2015-07-21
    • 2016-08-27
    相关资源
    最近更新 更多