Laravel使用auth:sanctum时自定义动态数据库中间件失效问题
问题原因
出现该问题的核心是两个Laravel的运行机制导致的:
- 中间件优先级:Laravel内核默认给
auth系列认证中间件设置了更高的执行优先级,即使你把database中间件写在路由组外层,实际请求到达时会先执行auth:sanctum再执行你的自定义中间件,此时认证用户需要查询数据库,但动态数据库配置还未被修改,直接读取了初始的空配置,就抛出了1045访问拒绝错误。 - 连接配置不匹配:你只修改了
multidomain连接的配置,但如果Sanctum使用的用户模型默认走的是全局默认数据库连接,没有切换到multidomain的话,即使中间件顺序正确也会读取旧的连接配置。
解决步骤
步骤1:调整中间件执行优先级
打开app/Http/Kernel.php,找到$middlewarePriority属性(如果没有就手动添加),将你的自定义database中间件放到所有认证相关中间件的最前面,确保它最先执行:
/** * 中间件优先级排序,靠前的先执行 * * @var array<int, class-string|string> */ protected $middlewarePriority = [ \App\Http\Middleware\Database::class, \Illuminate\Session\Middleware\StartSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, \Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests::class, \Illuminate\Routing\Middleware\ThrottleRequests::class, \Illuminate\Session\Middleware\AuthenticateSession::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, \Illuminate\Auth\Middleware\Authorize::class, ];
步骤2:修正动态数据库切换逻辑
修改你的Database中间件代码,补充默认连接切换、旧连接清空逻辑,同时增加SoftClient查询为空的异常捕获:
public function handle($request, Closure $next) { $route = app('router')->getRoutes()->match($request); $prefix = $route->action['name']; // 注意:SoftClient模型必须指定固定的主库连接,不能用动态切换的multidomain连接,避免死循环 // 可在SoftClient模型中添加 protected $connection = '你的主库连接名'; 实现 $s_client = SoftClient::where('url', $prefix)->firstOrFail(); \Config::set('database.connections.multidomain.host', $s_client->db_host ); \Config::set('database.connections.multidomain.database', $s_client->db_name ); \Config::set('database.connections.multidomain.username', $s_client->db_username ); \Config::set('database.connections.multidomain.password', $s_client->db_password ); // 将默认数据库连接切换为multidomain,确保auth:sanctum读这个连接 \Config::set('database.default', 'multidomain'); // 清空已存在的连接缓存 \DB::purge(); // 重新连接 \DB::reconnect(); return $next($request); }
步骤3:确认SoftClient模型配置
打开app/Models/SoftClient.php,手动指定该模型使用存储客户端配置的固定主库连接,不能使用动态切换的multidomain连接,避免查询客户端配置时找不到数据库:
class SoftClient extends Model { // 替换为你存客户端配置的主库连接名,比如mysql protected $connection = 'mysql'; // 其余原有代码保持不变 }
内容的提问来源于stack exchange,提问作者A S M Saief
相关产品推荐
相关产品推荐

