@ignaciodev It’s not discouraged, it’s just not how middleware works.
You should see middleware as “layers” that a request is passing through. The request either passes through a middleware, or a response is returned. A middleware shouldn’t know about any other middleware (or if there even is any other middleware), and definitely shouldn’t be trying to call other middleware, otherwise you may end up in an infinite loop.
For your case, you’re just describing authorisation. So either do the check in your controller action:
public function show(Request $request, VideoCall $videoCall)
{
}
Or create a dedicated middleware class that does the logic of checking if either the authenticated user is the owner of the model, or if the request has a valid signature:
use Closure;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use RuntimeException;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
class EnsureUserIsResourceOwnerOrRequestIsSigned
{
public function handle(Request $request, Closure $next, string $parameter)
{
$model = $request->route($parameter);
// Throw exception if requested route parameter is not a bound model
throw_unless(
condition: $model instanceof Model,
exception: new RuntimeException(
sprintf('Route parameter [%s] is not a model instance.', $parameter)
),
);
// First check if user is authenticated
// and that model's user relation equals the authenticated user
if (($user = $request->user()) && $model->user->is($user)) {
return $next($request);
}
// Otherwise check the request is signed
if ($request->hasValidSignature()) {
return $next($request);
}
// If we are here, user is neither owner nor is request signed
throw new AccessDeniedHttpException();
}
}
You would use this middleware by adding it to routes, and specifying the name of the route parameter you want to check the user for.
So, given the route:
Route::get('/video-calls/{video_call}', [VideoCallController::class, 'show']);
You’d do something like:
$this->middleware('resource_owner:video_call');