Skip to content

Instantly share code, notes, and snippets.

@adamtomat
Last active April 28, 2017 16:08
Show Gist options
  • Save adamtomat/36155879d4c602d3e65f166afbc70d69 to your computer and use it in GitHub Desktop.
Save adamtomat/36155879d4c602d3e65f166afbc70d69 to your computer and use it in GitHub Desktop.
Laravel Any/Or Middleware

Sometimes you may run into cases where you would like at least 1 middleware to pass from multiple middlewares.

Laravel cannot do this out of the box, so I created a middleware that proxies other middleware and passes as soon as one passes.

<?php
// This route requires either clientCredentials or auth (with the api guard) middleware to pass, rather than both
Route::get('/', 'ExampleController@index')->middleware('any:clientCredentials,auth:api');
<?php
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* @var array
*/
protected $routeMiddleware = [
// Some auth middleware
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
'clientCredentials' => \App\Http\Middleware\ClientCredentials::class,
'any' => \App\Http\Middleware\Any::class,
];
<?php
namespace App\Http\Middleware;
use Closure;
use Exception;
class Any
{
private $hasPassed;
private $caughtException;
public function __construct()
{
$this->hasPassed = false;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param array $parameters An array of middleware to apply
* @return mixed
*/
public function handle($request, Closure $next, ...$parameters)
{
// Loop through each middleware
collect($parameters)->each(function ($parameter) use ($request) {
// As soon as one middleware passes, don't bother checking the rest. One is all we need
if ($this->hasPassed) {
return false;
}
// Grab any parameters that have been passed into the given middleware
// e.g. for "auth:api", $middlewareParams would be ["api"]
$middlewareParts = explode(':', $parameter);
$middlewareParams = array_slice($middlewareParts, 1);
// Get an instance of the middleware class
$middleware = $this->getMiddleware($middlewareParts[0]);
try {
// See if the middleware passes
$middleware->handle($request, function () {
$this->hasPassed = true;
}, ...$middlewareParams);
} catch (Exception $e) {
$this->caughtException = $e;
}
});
// Forward the request on, if at least one of the middleware passed
if ($this->hasPassed) {
return $next($request);
}
// If any exceptions were thrown, re-throw the last one
if ($this->caughtException) {
throw $this->caughtException;
}
}
/**
* Get an instance off the middleware class
* @param The name of the middleware $name
* @return mixed
*/
private function getMiddleware($name)
{
$allMiddleware = app('router')->getMiddleware();
return app()->make(array_get($allMiddleware, $name));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment