Laravel 8中如何在模型boot方法获取中间件设置的非空Client Token
解决Laravel 8全局作用域中中间件变量未赋值的问题
你的问题核心在于模型的boot方法执行时机早于中间件:Laravel在应用启动阶段就会触发模型的boot方法,而中间件是在请求进入后才会执行,所以此时Client::$Current_Token还未被赋值,导致无法正确添加作用域。
直接有效的解决方案是将变量判断逻辑延迟到查询执行阶段,具体实现如下:
1. 修改全局作用域类,在apply方法中判断变量
不管boot方法是否注册作用域,每次查询时都会调用作用域的apply方法,此时中间件已经执行完毕,Client::$Current_Token已被设置:
<?php namespace App\Scopes; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Scope; use App\Client; class ClientTokenScope implements Scope { public function apply(Builder $builder, Model $model) { // 仅当Client::$Current_Token非空时,添加where条件 if (!empty(Client::$Current_Token)) { $builder->where('client_token', Client::$Current_Token); } } }
2. 在User模型的boot方法中直接注册全局作用域
无需在boot里做判断,直接注册作用域即可:
<?php namespace App\Models; use App\Scopes\ClientTokenScope; use Illuminate\Foundation\Auth\User as Authenticatable; class User extends Authenticatable { protected static function boot() { parent::boot(); // 直接注册全局作用域,判断逻辑交给apply方法处理 static::addGlobalScope(new ClientTokenScope()); } }
额外注意:静态变量的请求隔离问题
如果你的应用运行在Swoole、RoadRunner等常驻内存环境中,静态变量Client::$Current_Token可能会残留上一次请求的值,导致查询错误。更稳妥的做法是将客户端令牌存储在请求实例的属性中:
中间件中设置请求属性
<?php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; class SetClientToken { public function handle(Request $request, Closure $next) { // 从请求中获取令牌并存储到请求属性 $clientToken = $request->header('X-Client-Token'); $request->attributes->set('client_token', $clientToken); return $next($request); } }
修改作用域类获取请求属性
public function apply(Builder $builder, Model $model) { $clientToken = request()->attributes->get('client_token'); if (!empty($clientToken)) { $builder->where('client_token', $clientToken); } }
这样就能保证每个请求的令牌是独立的,避免常驻内存环境下的变量污染问题。
内容的提问来源于stack exchange,提问作者zarin
相关产品推荐
相关产品推荐

