为什么InitializeTenancyByDomain不适用于登录过程?

use*_*606 5 middleware routes multi-tenant laravel

这是针对具有 Stancl/Tenancy 的 Jetstream/Livewire 脚手架的 Laravel 8.x。租户模型或会话设置的初始化无法正常工作。要么是我没有做对,要么是内在的问题。

整个包是按照 Stencl/tenancy v3.x 的说明构建的。我可以按照下面概述的代码看到 dd(\App\User::all())

Route::middleware([ 
        'web',
        InitializeTenancyByDomain::class,
        PreventAccessFromCentralDomains::class,     
])->group(function (){
    
Route::get('/', function () { 
   dd(\App\User::all()); //can see all users models in tenants table
   return view('welcomeTenant'); 
});

Route::get('/home', [
    'middleware'  => ['auth'],
    'uses' => '\App\Http\Controllers\HomeController@index'
])->name('home');
                
});
Run Code Online (Sandbox Code Playgroud)

这对我来说意味着 InitializeTenancyByDomain 是对的。

当从租户的域请求登录表单时,例如。从 rtbs.example.in 来看,加密的会话/cookie 信息未存储在租户的会话表(即 rtbs.sessions)中。当发布登录表单时,它会在中央域(example.in)中查找用户表,其中不存在用户表,因此central.users表不存在错误。结果我收到 419 错误。我暂时禁用了 csrf 令牌验证来识别此问题。

这就是问题所在。为什么InitializeTenancyByDomain不适用于登录过程?我的基本设置有问题吗?有趣的是, dd(\App\User::all()) 如果出现在其他地方,即如下所示

Route::middleware([ 
        'web',
        InitializeTenancyByDomain::class,
        PreventAccessFromCentralDomains::class,     
])->group(function (){
    
dd(\App\User::all()); //central-domain.users does not exist error

Route::get('/', function () { 
    return view('welcomeTenant'); 
});

Route::get('/home', [
    'middleware'  => ['auth'],
    'uses' => '\App\Http\Controllers\HomeController@index'
])->name('home');
                
});
Run Code Online (Sandbox Code Playgroud)

抛出相同的 sql 异常,即central-domain.users 表不存在。仅当存在于 Route::get('/'... 内部时,我才能看到正确的模型。

Ror*_*ory 8

我在使用Laravel Fortify时遇到了这个问题,它为 JetStream 提供了后端。当我将会话驱动程序从文件更改为数据库时,这才成为问题 - 尽管这对于我的部署来说是必要的。

问题在于 Fortify 在其控制器的构造函数方法中广泛使用依赖注入。如Tenancy 文档中所述,由于 Laravel 请求的生命周期,当这些构造函数运行时,租赁将不可用。这意味着他们将默认使用中央连接并导致登录失败。

因为我们无法改变 Fortify 使用构造函数的方式,所以解决方案是将中间件更改为全局中间件,并在初始化中间件中添加对中心域的检查:

Stancl\Tenancy\Middleware\InitializeTenancyByDomain复制到App\Middleware\InitializeTenancyByDomain更改:

public function handle($request, Closure $next)
{

    //Skip for central domains
    if(in_array($request->getHost(), config('tenancy.central_domains'), true)){
        return $next($request);
    }


    return $this->initializeTenancy(
        $request, $next, $request->getHost()
    );
}
Run Code Online (Sandbox Code Playgroud)

App/Http/Kernel 使用App\Http\Middleware\InitializeTenancyByDomain;

protected $middleware = [
    // ...
    InitializeTenancyByDomain::class,
];
Run Code Online (Sandbox Code Playgroud)

配置/强化

use Stancl\Tenancy\Middleware\PreventAccessFromCentralDomains;

'middleware' => [
    'web',
    PreventAccessFromCentralDomains::class,
],
Run Code Online (Sandbox Code Playgroud)

路线/租户

Route::middleware([
        'web',
        PreventAccessFromCentralDomains::class,
    ])->group(function () {

        //Your Routes

    }
Run Code Online (Sandbox Code Playgroud)

借助此解决方案,Fortify 和 Stancl Tenancy 现在可以通过良好分离的数据库、会话和登录很好地协作。


Wat*_*man 0

该软件包非常有帮助,但需要大量工作才能将所有部件排列起来并进行维护。您已经拥有正确的中间件,包括“web”和两个租赁位,它们将启动会话并允许检查 CSRF。

我以前也遇到过类似的问题。对我来说最大的原因是它没有找到正确的“中心”路径,因此没有正确初始化租赁。

确保您的tenancy.php配置文件显示正确的中心域。就像是:

'central_domains' => [
     'example.in' // No http:// here
 ],
Run Code Online (Sandbox Code Playgroud)