Laravel 5: "Owner" multi-model middleware
I want to create middleware to check if an authenticated user is the owner of an item. For one model, the code is simple and looks something like this:
<?php namespace App\Http\Middleware;
use Closure;
class Owner {
public function handle($request, Closure $next)
{
$id = $request->segments()[1]; //get the id parameter
$model = Model::find($id); // find the model from DB
if(!$item)
return 'not found'; //if item not found
//check if authenticated user is owner
if($item->user_id == \Auth::id()){
return $next($request);
}else{
return 'not allowed';
}
}
}
Now let's say that I have multiple models (ModelX, ModelY, ModelZ) and I don't want to rewrite the middleware processing function multiple times. How would I embed a reference model in the middleware so that it can host multiple models from my application?
source to share
You can use route / model binding middleware options. Let's assume you have a message resource.
You determine the route. The middle software gets a parameter describing the resource with which you want to check ownership.
Route::get('/post/{post}', ['middleware' => 'owner:post', 'as' => 'post', 'uses' => 'PostController@showPost']);
Then you will bind your model to RouteServiceProvider.php:
$router->bind('post', function ($value) {
return Post::where('id', $value)->firstOrFail();
});
Finally, you would make middleware. It is important to know that the binding is made available in the request object as $ request-> post. Because you pass the name of the resource to the middleware, it becomes the third parameter in the descriptor method.
public function handle($request, Closure $next, $resource)
{
if ($request->{$resource}->user_id == \Auth::id()) {
return $next($request);
}
return response('not allowed.', 401);
}
I suppose you could also find the resource name programmatically, but using this method, your resource name and your route might be different.
source to share
You can use route and middleware options :
Retrieves middleware ( 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);
$userId = \DB::table($resourceName)->find($resourceId)->user_id;
if ($request->user()->id != $userId) {
abort(403, 'Unauthorized action.');
}
return $next($request);
}
}
Inside app\Http\Kernel.php
:
protected $routeMiddleware = [
'owner' => 'App\Http\Middleware\AbortIfNotOwner',
];
Inside the route file ( app/Http/routes.php
):
Route::group(['middleware' => ['owner:articles']], function() {
// your route
});
And maybe call it in your controller:
public function __construct()
{
$this->middleware('owner:articles', ['only' => ['edit', 'update']]);
}
source to share