I was facing an issue these days when I tried to pass arguments from my router to my middleware, to check if the authenticated user has the permissions to access that route.
How can I pass an argument from routes to the middleware?
I tried to do it and it works very well for me:
In my routes files:
Route::group(['prefix' => 'agenda', 'middleware' => 'auth', 'permissions' => 'user.create|user.delete'], function() {
//my routes here...
});
and inside the middleware:
class AuthMiddleware {
private $r;
private $guard;
public function __construct(Router $r, Guard $g)
{
$this->r = $r;
$this->guard = $g;
}
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$route = $this->r->getCurrentRoute();
$action = $route->getAction(); //$action['permissions'] is the string received from the routes file.
}
Related
I am trying to send some data from the handle function in a middleware:
<?php
namespace App\Http\Middleware;
class LanguageSwitcher
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (!Session::has('locale'))
{
Session::put('locale',Config::get('app.locale'));
}
App::setLocale(session('locale'));
$locale = session('locale'); // => The data I want to send
return $next($request);
}
}
My web.php:
Route::group(['middleware'=>'language'], function () {
// I want to set the prefix to locale here, but it's undefined
Route::group(['prefix' => $locale], function () {
});
});
I have tried to get the $locale in web.php using Session::get('locale') but I get Null.
So, is there any way to send it from the middleware to the route?
i guest you want to use locale for support multi language. You can do with set locale in middleware and use the locale in your route. Here is my example https://pastebin.pl/view/c5034cb9
I am using custom authentication middleware in API call, and I want to get the logged-in user Id.
here is my route:
Route::group(['middleware' => ['api', 'shopper']], function () {
Route::post('shopper/revieworder', 'ShoppersController#reviewOrder');
}
here is my middleware code :
<?php
namespace App\Http\Middleware;
use Closure;
use Response;
class ShopperMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
*
* #return mixed
*/
public function handle($request, Closure $next)
{
$data = array();
$data['token'] = $request->header('token');
$shoperValidationService
= resolve('App\Services\Validations\ShopperValidationService');
$responseService = resolve('App\Services\ResponseService');
$shopperRepo = resolve('App\Repositories\ShopperRepository');
$shoperValidationService->middleware($data);
$shopper = $shopperRepo->byToken($data['token']);
if (!$shopper) {
return $responseService->$this->response->fail('Invalid Token');
}
$request->merge([
"shopper_id" => $shopper->id,
"vendor_id" => $shopper->vendor_id,
]);
return $next($request);
}
}
I want to get the logged-id user id in "reviewOrder" function. Any help would be highly appreciable.
Is there a way to access a custom route parameter, same way as route "name": 'cache'=>true
Route::GET('tools/languages/{page?}', array('uses'=> 'Tools#list_languages', 'as'=>'list_languages', 'cache'=>true));
How to access cache value from Controller?
thanks,
Yes you can get your Route parameter from Middleware.
In your middleware you can get "matched route object" like this :
class MyMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$matchedRouteObject = $request->route();
$next($request);
}
}
See print_r($request->route()) there is a property that named action in this Route object. action property has all parameters of matched Route.
routes/web.php :
Route::get('tools/languages/{page?}', [
'uses' => 'Tools#list_languages',
'middleware' => 'App\Http\Middleware\MyMiddleware',
'cache' => 'value'
]);
app/Http/Middleware/MyMiddleware.php :
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Response;
class MyMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$matchedRouteObject = $this->route();
$deedVariable = $mathedRouteObject->action['cache']; // here you got your variable.
return $next($request);
}
}
Extending #Exprator answer, you could access the parameter in your controller as
public function list_languages(Request $request)
{
$request->route()->getAction()['cache']; // returns true
}
https://laravel.com/api/5.4/Illuminate/Routing/Route.html#method_getAction
I've got a middleware setup that's caching the HTML output of each public Controller request, in each of my controllers' __construct method.
public function __construct() {
$this->middleware('auth', ['except' => ['index', 'show']]);
$this->middleware('cache.get', ['only' => 'show']);
$this->middleware('cache.put', ['only' => 'show']);
}
The caching is working great, as expected, except for one thing: I've got Route-Model bindings setup in RouteServiceProvider.php for easy accessiblity of models in their respective controllers, like
public function boot(Router $router)
{
parent::boot($router);
$router->bind('posts', function($id) {
return \App\Article::findBySlugOrIdOrFail($id);
});
$router->bind('tags', function($name) {
return \App\Tag::where('name', $name)->firstOrFail();
});
$router->bind('artists', function($slug) {
return \App\Artist::findBySlugOrIdOrFail($slug);
});
Basically what's happening is even when pages are cached, I'm still getting a single query for each route where it's looking up that slug (SluggableInterface) or id. Wondering if there's a way to do this where the query doesn't occur when a route is cached? Or is that just not possible?
Thanks!
EDIT
Here's my caching middleware:
class GetCache
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$key = StringHelper::keygen($request->path());
if (Cache::has($key) && Auth::guest()) {
$content=Cache::get($key);
return response($content);
}
return $next($request);
}
}
class PutCache
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$response = $next($request);
$key = StringHelper::keygen($request->path());
if (! Cache::has($key) && Auth::guest()) {
Cache::put($key, $response->getContent(), 600);
}
return $next($request);
}
}
I'm having a trouble with creating the "owner" middleware.
For example, I have a Articles and Usermodel associated with user_id key.
I want to add the "owner" middleware to the ArticlesController, so the only owner of that article can edit, update and delete it.
I've been searching for this issue for a while, but never found the code, which would work.
Some of them tried to make it work with Form Requests, but I'm interested in using Middleware.
Create middleware:
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);
}
}
Add it to app\Http\Kernel.php:
protected $routeMiddleware = [
'owner' => 'App\Http\Middleware\OwnerMiddleware',
];
Use middleware in your routes:
Route::group(['middleware' => ['owner']], function() {
// your route
});
Alternatively you could use route and middleware parameters, it has some advantages:
Even if the request structure changes your middleware would still work
The middleware is reusable for differents resources
You can use it inside controllers
Here’s the 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);
$user_id = \DB::table($resourceName)->find($resourceId)->user_id;
if ($request->user()->id != $user_id) {
abort(403, 'Unauthorized action.');
}
return $next($request);
}
}
Inside app\Http\Kernel.php:
protected $routeMiddleware = [
'owner' => 'App\Http\Middleware\AbortIfNotOwner',
];
Inside your route file (app/Http/routes.php):
Route::group(['middleware' => ['owner:articles']], function() {
// your route
});
And optionally call it in the controller:
public function __construct()
{
$this->middleware('owner:articles', ['only' => ['edit', 'update']]);
}