如何解决中间件之前的 laravel 表单请求
我知道,这是一个复杂的案例,但也许你们中的一个人可能知道如何做到这一点。
概念
我的 API 中有以下流程:
- 处理查询字符串参数(
FormRequest
) - 检查是否允许用户执行请求 (
Middleware
)- 使用已处理(经过验证和清理)的查询参数 → 否则,我必须对每个可能的别名和映射进行异常处理,并检查是否检查了参数,这对我来说似乎不合理。
问题
然而,如果您只是通过 ->middleware('middlewareName')
将中间件分配给路由,并将 FormRequest 通过依赖注入分配给控制器方法,则首先调用中间件,然后调用 FormRequest。如上所述,这不是我需要的。
解决方法
我第一次尝试在中间件上进行依赖注入,但没有成功。
我的解决方案是在控制器构造函数中分配中间件。依赖注入在这里有效,但突然 Auth::user()
返回 null
。
然后,我遇到了 FormRequest::createFrom($request)
中的 \Illuminate\Foundation\Providers\FormRequestServiceProvider.PHP:34
方法以及将 $request
对象传递给中间件的 handle()
方法的可能性。结果如下:
public function __construct(Request $request)
{
$middleware = new MyMiddleware();
$request = MyRequest::createFrom($request);
$middleware->handle($request,function() {})
}
但现在请求尚未验证。只是调用 $request->validated()
没有任何回报。所以我深入挖掘了一下,发现 $resolved->validateResolved();
是在 \Illuminate\Foundation\Providers\FormRequestServiceProvider.PHP:30
中完成的,但这似乎并没有触发验证,因为它抛出了一个异常,说这个方法不能在 null
上调用但 $request 不是 null
:
现在,我完全被难住了。有谁知道如何解决这个问题,还是我做错了?
提前致谢!
解决方法
我想,我想出了一个更好的方法来做到这一点。
我的误解
当中间件进行身份验证时,我在那里进行授权,因此我必须使用 Gate
结果代码
控制器
...
public function getData(MyRequest $request)
{
$filters = $request->query();
// execute queries
}
...
表单请求
class MyRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return Gate::allows('get-data',$this);
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
// ...
];
}
/**
* Prepare the data for validation.
*
* @return void
*/
protected function prepareForValidation()
{
$this->replace($this->cleanQueryParameters($this->query()));
}
private function cleanQueryParameters($queryParams): array
{
$queryParams = array_filter($queryParams,function($param) {
return is_array($param) ? count($param) : strlen($param);
});
$defaultStartDate = (new \DateTime())->modify('monday next week');
$defaultEndDate = (new \DateTime())->modify('friday next week');
$defaults = [
'article.created_by_id' => self::getDefaultEmployeeIds(),'date_from' => $defaultStartDate->format('Y-m-d'),'date_to' => $defaultEndDate->format('Y-m-d')
];
$aliases = [
// ...
];
$mapper = [
// ...
];
foreach($aliases as $alias => $key) {
if (array_key_exists($alias,$queryParams)) {
$queryParams[$key] = $queryParams[$alias];
unset($queryParams[$alias]);
}
}
foreach($mapper as $key => $fn) {
if (array_key_exists($key,$queryParams)) {
$fn($queryParams,$key);
}
}
$allowedFilters = array_merge(
Ticket::$allowedApiParameters,array_map(function(string $param) {
return 'article.'.$param;
},TicketArticle::$allowedApiParameters)
);
$arrayProps = [
// ..
];
foreach($queryParams as $param => $value) {
if (!in_array($param,$allowedFilters) && !in_array($param,['date_from','date_to'])) {
abort(400,'Filter "'.$param.'" not found');
}
if (in_array($param,$arrayProps)) {
$queryParams[$param] = guarantee('array',$value);
}
}
return array_merge($defaults,$queryParams);
}
}
门
class MyGate
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Auth\Access\Response|Void
* @throws \Symfony\Component\HttpKernel\Exception\HttpException
*/
public function authorizeGetDataCall(User $user,MyRequest $request): Response
{
Log::info('[MyGate] Checking permissions …');
if (in_array(LDAPGroups::Admin,session('PermissionGroups',[]))) {
// no further checks needed
Log::info('[MyGate] User is administrator. No further checks needed');
return Response::allow();
}
if (
($request->has('group') && !in_array(Group::toLDAPGroup($request->get('group')),[]))) ||
$request->has('owner.department') && !in_array(Department::toLDAPGroup($request->query('owner.department')),[])) ||
$request->has('creator.department') && !in_array(Department::toLDAPGroup($request->query('creator.department')),[]))
) {
Log::warning('[MyGate] Access denied due to insufficient group/deparment membership',[ 'group/department' =>
$request->has('group') ?
Group::toLDAPGroup($request->get('group')) :
($request->has('owner.department') ?
Department::toLDAPGroup($request->query('owner.department')) :
($request->has('creator.department') ?
Department::toLDAPGroup($request->query('creator.department')) :
null))
]);
return Response::deny('Access denied');
}
if ($request->has('customer_id') || $request->has('article.created_by_id')) {
$ids = [];
if ($request->has('customer_id')) {
$ids = array_merge($ids,$request->query('customer_id'));
}
if ($request->has('article.created_by_id')) {
$ids = array_merge($ids,$request->query('article.created_by_id'));
}
$users = User::find($ids);
$hasOtherLDAPGroup = !$users->every(function($user) {
return in_array(Department::toLDAPGroup($user->department),[]));
});
if ($hasOtherLDAPGroup) {
Log::warning('[MyGate] Access denied due to insufficient permissions to see specific other user\'s data',[ 'ids' => $ids ]);
return Response::deny('Access denied');;
}
}
if ($request->has('owner.login') || $request->has('creator.login')) {
$logins = [];
if ($request->has('owner.login')) {
$logins = array_merge(
$logins,guarantee('array',$request->query('owner.login'))
);
}
if ($request->has('creator.login')) {
$logins = array_merge(
$logins,$request->query('creator.login'))
);
}
$users = User::where([ 'samaccountname' => $logins ])->get();
$hasOtherLDAPGroup = !$users->every(function($user) {
return in_array(Department::toLDAPGroup($user->department),[ 'logins' => $logins ]);
return Response::deny('Access denied');
}
}
Log::info('[MyGate] Permission checks passed');
return Response::allow();
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。