Search code examples
phplaravelrouteslaravel-permission

How can I add OR relationship in laravel middleware for a Route


I'm using spatie/laravel-permission to add permissions for my routes.

One of the routes I have can be accessed by two permissions (earnings, financial_fund). The user doesn't need to have both permissions to access the controller. He can access the controller by having one of the permissions or both of them.

I've tried to write something like this.

Route::group(['middleware' => ['can:earnings']], function () {
    Route::get('/payment', [PaymentsController::class, 'getAll']);
    Route::post('/payment/cash', [PaymentsController::class, 'addCashPayment']);
});
Route::group(['middleware' => ['can:financial_fund']], function () {
    Route::get('/payment', [PaymentsController::class, 'getAll']);
    Route::post('/payment/cash', [PaymentsController::class, 'addCashPayment']);
});

But the above code allows only users with can:earnings permission to access the routes, it doesn't allow users with can:financial_fund permission.

I've also tried to write something like this

Route::group(['middleware' => ['can:earnings,financial_fund']], function () {
    Route::get('/payment', [PaymentsController::class, 'getAll']);
    Route::post('/payment/cash', [PaymentsController::class, 'addCashPayment']);
});

But this requires both of permissions to exist with the current user.

How can I tell that I want only one of the permissions at least to exist?

I have found that Laravel has introduced the canAny for use in blade templates. Is there a way I can use it in my api.php file while defining the Routes?


Solution

  • I fixed it by creating a new middleware

    namespace App\Http\Middleware;
    
    use Closure;
    use Illuminate\Http\Request;
    
    class AuthorizeCanAny
    {
        public function handle(Request $request, Closure $next, ...$permissions)
        {
            if (!$request->user()) {
                abort(403);
            }
    
            $userPermissions = array_map(function ($e) {
                return $e['name'];
            }, $request->user()->permissions->toArray());
    
            $userPermissionsIntersect = array_intersect($userPermissions, $permissions);
    
            if (!sizeof($userPermissionsIntersect)) {
                abort(403);
            }
    
            return $next($request);
        }
    }
    

    Adding the middleware to kernal.php file

    protected $routeMiddleware = [
        ...,
        'canAny' => AuthorizeCanAny::class,
    ];
    

    Then use it in the router

    Route::group(['middleware' => ['canAny:earnings,financial_fund']], function () {
        Route::get('/payment', [PaymentsController::class, 'getAll']);
        Route::post('/payment/cash', [PaymentsController::class, 'addCashPayment']);
    });