You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel中Sanctum认证前基于db_slug切换客户端数据库的实现问题

问题根因

Laravel 默认存在中间件优先级规则,auth 类认证中间件的优先级高于普通自定义中间件,即使你在路由组中将 clientDB 写在 auth:sanctum 前面,实际执行时仍会优先运行认证逻辑,此时数据库尚未切换,自然会从主库查询用户导致认证失败。


解决方案

第一步:调整中间件优先级

打开 app/Http/Kernel.php,找到 $middlewarePriority 属性,将你的自定义中间件添加到 Authenticate 认证中间件之前,强制它优先执行:

protected $middlewarePriority = [
    \App\Http\Middleware\ClientDBMiddleware::class, // 新增到数组最顶部
    \Illuminate\Cookie\Middleware\EncryptCookies::class,
    \Illuminate\Session\Middleware\StartSession::class,
    \Illuminate\View\Middleware\ShareErrorsFromSession::class,
    \Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests::class,
    // 其余原有配置保持不变
];

第二步:优化中间件逻辑

原中间件缺少校验和重连逻辑,优化后代码如下:

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use DB;
use Config;

class ClientDBMiddleware
{
    public function handle(Request $request, Closure $next)
    {
        // 校验必填参数
        if(!$request->has('db_slug')){
            abort(400, '缺少租户参数');
        }
        $dbSlug = $request->input('db_slug');
        
        // 可选:从主库租户表校验db_slug合法性,避免非法请求
        // if (!\App\Models\Tenant::where('slug', $dbSlug)->exists()) {
        //     abort(404, '租户不存在');
        // }

        // 重置连接、更新配置、显式重连
        DB::purge('mysql');
        Config::set('database.connections.mysql.database', "db_{$dbSlug}");
        DB::reconnect('mysql');

        // 可选:校验数据库连接有效性
        try {
            DB::connection('mysql')->getPdo();
        } catch (\Exception $e) {
            abort(500, '租户数据库连接失败');
        }

        return $next($request);
    }
}

更优方案:多连接隔离主库与租户库(推荐)

直接修改默认连接容易导致主应用操作串库,建议单独配置租户连接实现完全隔离:

  1. 打开 config/database.php 新增租户连接配置:
'connections' => [
    // 原有主库mysql配置保持不变
    'tenant' => [
        'driver' => 'mysql',
        'host' => env('DB_HOST', '127.0.0.1'),
        'port' => env('DB_PORT', '3306'),
        'username' => env('DB_USERNAME', 'root'),
        'password' => env('DB_PASSWORD', ''),
        'charset' => 'utf8mb4',
        'collation' => 'utf8mb4_unicode_ci',
        'strict' => true,
        // database 留空,中间件动态赋值
    ],
]
  1. 所有租户侧模型(包括客户端用户模型、Sanctum token 模型)指定连接为 tenant:
// 租户模型内添加属性
protected $connection = 'tenant';
  1. 修改 config/sanctum.php 配置,让认证逻辑读取租户库的token:
'storage' => [
    'database' => [
        'connection' => 'tenant',
        'table' => 'personal_access_tokens',
    ],
],
  1. 调整中间件逻辑,仅修改租户连接配置:
DB::purge('tenant');
Config::set('database.connections.tenant.database', "db_{$dbSlug}");
DB::reconnect('tenant');

内容的提问来源于stack exchange,提问作者John

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 04:48:04