Laravel - 如何将附加参数传递给 Gate 以保持其原始类型?
Laravel - How to pass additional parameters to Gate keeping their original types?
我正在尝试从某个控制器向 Gate
传递一个附加参数。
我得到的一个错误和部分stack trace如下:
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))
问题是 $request
(如下所示)以字符串形式出现 Gate
,而不是 Request
类型。在 Gate
中使用 dd
函数(并暂时删除类型提示),我发现 $request
的值只是一个无用的文本:"Illuminate\Http\Request"
.
如何将 $request
传递给 Gate
并保持 Request
类型?
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');
注:
如果我直接在控制器内部使用Gate
(如下所示),它工作正常。但是,由于我们团队的规定,我必须通过 api.php 使用 Gate
。你有什么想法吗?
SomeController.php(一个工作示例)
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(一个工作示例)
(同上)
api.php(一个工作示例)
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\SomeController;
Route::post('/foo-events', [SomeController::class, 'fooEvents'])
->name('foo-events');
我对解析为 Illuminate\Auth\Middleware\Authorize
的 can
中间件进行了一些测试。
如果提供了类名(路由模型绑定)或路由参数(例如:my_route/{my_param}
,您可以用can:foo,my_param
).
如您所述,如果您的门是从您的控制器调用的,您可以将请求作为参数传递。但是从使用“can”中间件的路由定义中,我无法将整个请求对象作为参数。
您仍然可以在门方法中使用助手 request()
来访问整个请求。
一些细节here和阅读src/Illuminate/Auth/Middleware/Authorize.php
getGateArguments()
方法。
请注意,您还可以将政策附加到您的大门,并使用 request()
助手。
我对门不是很熟悉,但是 can
中间件与策略一起使用。它可以传递参数,但这些是路由参数,如 the canonical example:
Route::put('/post/{post}', function (Post $post) {
// The current user may update the post...
})->middleware('can:update,post');
post
被定义为路由参数,因此当它被添加到 can
中间件时,该模型作为参数传递给策略。
在不需要模型实例的情况下,class 的名称将作为参数传递给策略,除非使用路由模型绑定,在这种情况下它将是一个新实例给定的 class。同样,这被政策使用,而不是 AFAIK 门,并且不会给你当前的请求对象。
获取当前请求实例的常用方法是使用the request()
helper。只需将您的代码修改为如下所示:
Gate::define('foo', function (?User $user) {
$request = request();
/* some processes */
});
我正在尝试从某个控制器向 Gate
传递一个附加参数。
我得到的一个错误和部分stack trace如下:
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))
问题是 $request
(如下所示)以字符串形式出现 Gate
,而不是 Request
类型。在 Gate
中使用 dd
函数(并暂时删除类型提示),我发现 $request
的值只是一个无用的文本:"Illuminate\Http\Request"
.
如何将 $request
传递给 Gate
并保持 Request
类型?
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');
注:
如果我直接在控制器内部使用Gate
(如下所示),它工作正常。但是,由于我们团队的规定,我必须通过 api.php 使用 Gate
。你有什么想法吗?
SomeController.php(一个工作示例)
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(一个工作示例)
(同上)
api.php(一个工作示例)
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\SomeController;
Route::post('/foo-events', [SomeController::class, 'fooEvents'])
->name('foo-events');
我对解析为 Illuminate\Auth\Middleware\Authorize
的 can
中间件进行了一些测试。
如果提供了类名(路由模型绑定)或路由参数(例如:my_route/{my_param}
,您可以用can:foo,my_param
).
如您所述,如果您的门是从您的控制器调用的,您可以将请求作为参数传递。但是从使用“can”中间件的路由定义中,我无法将整个请求对象作为参数。
您仍然可以在门方法中使用助手 request()
来访问整个请求。
一些细节here和阅读src/Illuminate/Auth/Middleware/Authorize.php
getGateArguments()
方法。
请注意,您还可以将政策附加到您的大门,并使用 request()
助手。
我对门不是很熟悉,但是 can
中间件与策略一起使用。它可以传递参数,但这些是路由参数,如 the canonical example:
Route::put('/post/{post}', function (Post $post) {
// The current user may update the post...
})->middleware('can:update,post');
post
被定义为路由参数,因此当它被添加到 can
中间件时,该模型作为参数传递给策略。
在不需要模型实例的情况下,class 的名称将作为参数传递给策略,除非使用路由模型绑定,在这种情况下它将是一个新实例给定的 class。同样,这被政策使用,而不是 AFAIK 门,并且不会给你当前的请求对象。
获取当前请求实例的常用方法是使用the request()
helper。只需将您的代码修改为如下所示:
Gate::define('foo', function (?User $user) {
$request = request();
/* some processes */
});