PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Friday, February 4, 2022

[FIXED] Laravel - How to pass additional parameters to Gate keeping their original types?

 February 04, 2022     authorization, laravel, laravel-8, php     No comments   

Issue

I'm trying to pass an additional argument to Gate from some controller.

An error and a part of stack trace I got are as follows:

testing.ERROR: App\Providers\AuthServiceProvider::App\Providers\{closure}(): Argument #2 ($request) must be of type Illuminate\Http\Request, string given, called in /var/www/html/vendor/laravel/framework/src/Illuminate/Auth/Access/Gate.php on line 477 {"exception":"[object] (TypeError(code: 0): App\\Providers\\AuthServiceProvider::App\\Providers\\{closure}(): Argument #2 ($request) must be of type Illuminate\\Http\\Request, string given, called in /var/www/html/vendor/laravel/framework/src/Illuminate/Auth/Access/Gate.php on line 477 at /var/www/html/app/Providers/AuthServiceProvider.php:74)
[stacktrace]
#0 /var/www/html/vendor/laravel/framework/src/Illuminate/Auth/Access/Gate.php(477): App\\Providers\\AuthServiceProvider->App\\Providers\\{closure}(NULL, 'Illuminate\\\\Http...')
#1 /var/www/html/vendor/laravel/framework/src/Illuminate/Auth/Access/Gate.php(372): Illuminate\\Auth\\Access\\Gate->callAuthCallback(NULL, 'foo', Array)
#2 /var/www/html/vendor/laravel/framework/src/Illuminate/Auth/Access/Gate.php(337): Illuminate\\Auth\\Access\\Gate->raw('foo', Array)
#3 /var/www/html/vendor/laravel/framework/src/Illuminate/Auth/Access/Gate.php(324): Illuminate\\Auth\\Access\\Gate->inspect('foo', Array)
#4 /var/www/html/vendor/laravel/framework/src/Illuminate/Auth/Middleware/Authorize.php(43): Illuminate\\Auth\\Access\\Gate->authorize('foo', Array)
#5 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Auth\\Middleware\\Authorize->handle(Object(Illuminate\\Http\\Request), Object(Closure), 'foo', 'Illuminate\\\\Http...')
#6 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php(50): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#7 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Routing\\Middleware\\SubstituteBindings->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#8 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php(127): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#9 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php(103): Illuminate\\Routing\\Middleware\\ThrottleRequests->handleRequest(Object(Illuminate\\Http\\Request), Object(Closure), Array)
#10 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php(55): Illuminate\\Routing\\Middleware\\ThrottleRequests->handleRequestUsingNamedLimiter(Object(Illuminate\\Http\\Request), Object(Closure), 'api', Object(Closure))

The problem is that $request (shown below) comes to Gate as string, not Request type. Using dd function inside Gate (and temporarily removing the type hint), I found the value of $request was merely a useless text: "Illuminate\Http\Request".

How can I pass $request to Gate keeping Request type?

SomeController.php

use Illuminate\Http\Request;
use Illuminate\Http\Response;
use App\Http\Controllers\Controller;

class SomeController extends Controller
{
    public function fooEvents(Request $request): Response
    {
        /* some processes */
    }
}

AuthServiceProvider.php

use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;

public function boot()
{
    $this->registerPolicies();

    /**
     * @param \App\Models\User $user
     * @param Illuminate\Http\Request $request
     * @return bool
     */
    Gate::define('foo', function (?User $user, Request $request) {

        /**
         * The problem is that the argument $request comes here as string type,
         * while I want it as Illuminate\Http\Request type;
         */

        /* some processes */
    });
}

api.php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\SomeController;

Route::post('/foo-events', [SomeController::class, 'fooEvents'])
    ->middleware('can:foo,Illuminate\Http\Request')
    ->name('foo-events');

Note:

If I directly use Gate inside the controller (shown below), it works fine. However I have to use Gate via api.php due to our team's rule. Do you have any idea?

SomeController.php (A working example)

use Illuminate\Http\Request;
use Illuminate\Http\Response;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Gate;

class SomeController extends Controller
{
    public function fooEvents(Request $request): Response
    {
        if (!Gate::allows('foo', $request)) {
            return abort(404);
        }

        /* some processes */
    }
}

AuthServiceProvider.php (A working example)

(The same as the previous one)

api.php (A working example)

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\SomeController;

Route::post('/foo-events', [SomeController::class, 'fooEvents'])
    ->name('foo-events');

Solution

I did some tests on the can middleware that resolves to Illuminate\Auth\Middleware\Authorize.

It seems it can return a class_name if a className is provided (route model binding), or a route parameter (eg: my_route/{my_param}, you can define your Gate with can:foo,my_param).

As you stated, you could pass the request as a parameter if your gate was called from your controller. But from the route definition using the "can" middleware, I wasn't able to get the entire request object as parameter.

Still, you can use the helper request() in your gate method to access the entire request.

Some details here and reading the src/Illuminate/Auth/Middleware/Authorize.php getGateArguments() method.

Note that you could also attach a Policy to your gate, and use the request() helper.



Answered By - Mtxz
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing