0

我在 Laravel 5.1 中有几个由模型表示的资源。模型都有 account_id 和 user_id。有一个 user_account 的数据透视表,表示帐户和用户之间的关系。

我在 routes.php 中有我的路由,它们是资源控制器,例如 route.asset。

我希望为所有这些控制器创建一个中间件,这样我可以在 => ['belongstoaccount']

在那个中间件中它应该检查:

用户属于 account.asset 中的帐户(我目前在控制器中使用 ->contains() 。)

资产的 account_id 与 account->id 匹配。

我想为所有这些资产制作一个中间件。这甚至可能吗?我应该在 $request 中查找此信息吗?

感谢您的任何指导,

乔什

4

1 回答 1

1

这实际上并不太难,但它确实需要一些设置才能使中间件能够检测到正在加载的资源。这是通过使用Route-Model Binding完成的

示例资源路由:

Route::group(['middleware' => 'BelongsToAccount'], function() {
    Route::resource('asset', 'AssetController');
    Route::resource('liability', 'LiabilityController');
});

现在,我们需要绑定资源,RouteServiceProvider以便我们的路由加载资源:

   /**
     * Define your route model bindings, pattern filters, etc.
     *
     * @param  \Illuminate\Routing\Router  $router
     * @return void
     */
    public function boot(Router $router)
    {
        parent::boot($router);
        // bound models
        $router->model('asset', 'App\Asset');
        $router->model('liability', 'App\Liability');
    }

现在转到中间件的handle方法并转储$request->route()->parameters();。您应该会看到参数列表中列出的资源。使用请求中可用的资源实例,最后一步是在中间件中检查并验证它:

<?php namespace App\Http\Middleware;

use Closure;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Contracts\Routing\Middleware;
class BelongsToAccount implements Middleware {
    /**
     * 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)
    {
        // get the resource from the route
        $resource = $this->getResource($request);

        if (!empty($resource))
        {
            if ($this->auth->user()->accountId == $resource->accountId)
            {
                return $next($request);
            }
        }
    }

    /**
     * Get resource from route if it exists
     *
     * @param  \Illuminate\Http\Request  $request
     * @return mixed
     */
    public function getResource($request)
    {
        foreach ($request->route()->parameters() as $param)
        {
            if ($param instanceof Model) return $param;
        }

        return null;
    }
}

上面的代码不是即插即用的,您可能需要准确更改accountId从当前登录用户获取值的方式等。但是这里发生的事情的要点是添加了一个额外的方法来查找实例的一个Eloquent\Model。找到后,它会返回此资源以供中间件使用,并假定该资源已经绑定了一个 accountId。

如果您想要更精细的控制,我建议将中间件移至控制器__construct,以更具体地调整它所处理的控制器操作。不过,您也可以在路由文件中完成此操作。

希望这可以帮助!

于 2015-12-30T02:13:57.563 回答