如何在几分钟内使 Laravel 应用拥有多租户功能

Laravel

在本教程中,我们将使用 Tenancy for Laravel package让Laravel 应用实现多租户。

它是一个多租户软件包,让你的Laravel应用程序实现多租户 不需要复写额外代码。 它就像租赁包一样即插即用。

旁注:在本教程中,我们将介绍最常见的设置-多个域上的多数据库租赁。如果你需要一个不同的设置,这是100%可能的。只需查看文件包。

工作原理

这个包的独特之处在于它不会强迫您以特定的方式编写应用程序。你可以像你习惯的那样编写你的应用程序,它会在后台自动生成多租户。您甚至可以将包集成到现有的应用程序中。

以下是它的工作原理:

  1. 当服务器接收到用户请求
  2. 程序便可以通过请求识别该请求属于哪个租户。(通过主域名,子域名,路径,请求头,query 参数,等)
  3. 程序将会从 default 数据库链接切换为当前租户链接。
  4. 任意的数据库调用,缓存调用,队列调用,等操作都会自动匹配租户并切换。

安装

第一步,通过 composer 安装 package,命令如下:

composer require stancl/tenancy

然后,执行 tenancy:install 命令,如下:

php artisan tenancy:install

该操作会产生以下文件:迁移文件,配置文件,路由文件和一个服务提供者。

下面让我们把数据库建立起来,通过以下命令执行数据库迁移:

php artisan migrate

然后在 config/app.php注册服务提供者。请确定将代码放于以下位置:

/*
 * Application Service Providers...
 */
App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class,
// App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
App\Providers\TenancyServiceProvider::class, // <-- 放于此处

现在,我们创建一个自定义的 tenant 模型。该程序包是不受限制的,因此要使用单独的数据库和域,我们需要创建一个略微定制的 tenant 模型。使用以下代码创建一个 app/Tenant.php 文件:

<?php

namespace App;

use Stancl\Tenancy\Database\Models\Tenant as BaseTenant;
use Stancl\Tenancy\Contracts\TenantWithDatabase;
use Stancl\Tenancy\Database\Concerns\HasDatabase;
use Stancl\Tenancy\Database\Concerns\HasDomains;

class Tenant extends BaseTenant implements TenantWithDatabase
{
    use HasDatabase, HasDomains;
}

现在,我们告诉程序包将该模型用于 tenants:

// config/tenancy.php file

'tenant_model' => \App\Tenant::class,

两个部分

软件包将您的应用程序视为两个独立的部分:

  • central 应用程序 —— 承载登录页面,可能是管理 tenants 的中央仪表板等
  • tenant 应用程序 —— 这是您的用户 (tenants) 使用的部分。这很可能是大多数业务逻辑都存在的地方

拆分应用

了解了这两个部分,让我们将应用进行相应的拆分。

Central app

首先让我们确保 central 应用仅在中心域上可访问。

转到 app/Providers/RouteServiceProvider.php,并确保您的 webapi 路由仅在中央域上加载:

protected function mapWebRoutes()
{
    foreach ($this->centralDomains() as $domain) {
        Route::middleware('web')
            ->domain($domain)
            ->namespace($this->namespace)
            ->group(base_path('routes/web.php'));
    }
}

protected function mapApiRoutes()
{
    foreach ($this->centralDomains() as $domain) {
        Route::prefix('api')
            ->domain($domain)
            ->middleware('api')
            ->namespace($this->namespace)
            ->group(base_path('routes/api.php'));
    }
}

protected function centralDomains(): array
{
    return config('tenancy.central_domains');
}

现在转到您的文件 config/tenancy.php,实际添加中心域。

我使用的是 Valet,所以对我来说,中心域是 saas.test,租户域以 foo.saas.testbar.saas.test 为例。

因此,我们设置 central_domains 键:

'central_domains' => [
    'saas.test', // Add the ones that you use. I use this one with Laravel Valet.
],

Tenant app

现在是有趣的部分。这一部分几乎太简单了。

要使某些代码具有租户意识,您只需执行以下操作:

  • 将迁移移动到 tenant/ 目录
  • 将路由移动到 tenant.php 路由文件

就是这样。

在该特定文件夹中进行迁移并且在该特定路由文件中包含路由将通知包标识该路由上的租户。

如果您有现有的应用程序,请使用您的代码执行此操作。如果您使用的是全新应用,请按照以下示例操作:

默认情况下,您的租户路由如下所示:

Route::middleware([
    'web',
    InitializeTenancyByDomain::class,
    PreventAccessFromCentralDomains::class,
])->group(function () {
    Route::get('/', function () {
        return 'This is your multi-tenant application. The id of the current tenant is ' . tenant('id');
    });
});

这些路由只能在 tenant (非中心) 域上访问 —— PreventAccessFromCentralDomains 中间件会强制执行这一点。

让我们做一点小更改以转储数据库中的所有用户,以便我们可以实际看到多租户工作。将此添加到中间件组:

Route::get('/', function () {
    dd(\App\User::all());
    return 'This is your multi-tenant application. The id of the current tenant is ' . tenant('id');
});

现在,迁移。只需将与租户应用程序相关的迁移移动到database/migrations/tenant目录中即可。

因此,对于我们的示例:要使用户进入租户数据库,让我们将users表迁移移至数据库/迁移/租户。这将防止在中央数据库中创建表,而是在创建租户时在租户数据库中创建表。

尝试一下

现在让我们创建一些租户。

我们还没有可供租户注册的登录页面,但是我们可以在修补程序中创建他们!

因此,让我们打开php artisan tinker并创建一些租户。租户实际上只是模型,因此您可以像其他任何Eloquent模型一样创建它们。

请注意,我们在 这里使用域标识因此,请确保您使用的域指向您的应用程序。我正在使用代客,所以我正在*.saas.test用于租户。如果使用php artisan serve,则可以使用foo.localhost

    >> $tenant1 = Tenant::create(['id' => 'foo']);
    >> $tenant1->domains()->create(['domain' => 'foo.saas.test']);
>>>
    >> $tenant2 = Tenant::create(['id' => 'bar']);
    >> $tenant2->domains()->create(['domain' => 'bar.saas.test']);

现在,我们将在每个租户的数据库中创建一个用户:

App\Tenant::all()->runForEach(function () {
    factory(App\User::class)->create();
});

就是这样-  我们有一个多租户应用程序!

如果您访问  foo.saas.test (或与您的环境相当),则会看到用户转储。

如果访问bar.saas.test,您将看到不同用户的转储 。数据库是100%分离的,我们使用的代码 —App\User::all()— 根本不需要了解租约!这一切都会在后台自动发生。您只需像以前那样编写应用程序,而不必考虑自己的范围界定,并且一切都正常。

当然,现在,租户应用程序中将有一个更复杂的应用程序。仅转储用户的SaaS可能用处不大。这就是您的工作-编写将由租户使用的业务逻辑。包装将处理其余部分。

不过,Tenancy for Laravel 项目的帮助并没有到此结束。该软件包将为您完成与多租户相关的所有繁重工作。但是,如果您要构建SaaS,则仍然需要自己编写计费逻辑,入门流程和类似的标准内容。如果您有兴趣,该项目还提供了一个优质产品:multi-tenant SaaS boilerplate。它旨在通过为您提供通常需要编写的SaaS功能来节省您的时间。所有这些都打包在一个随时可以部署的多租户应用程序中。您可以在这里阅读更多有关它的信息

最后说明:本教程旨在向您展示创建多租户应用程序有多么简单。为了您的阅读舒适,本书尽量简短。有关更多详细信息,请阅读软件包的快速入门教程文档

祝你的SaaS好运!

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://laravel-news.com/multi-tenant

译文地址:https://learnku.com/laravel/t/47951

本帖已被设为精华帖!
本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 8

目前正在使用这个扩展库当中,就是文件存储这块看的不是很懂

3年前 评论
pangxianfei

报404。

Laravel

3年前 评论
91it 3年前
xingchenboy 2年前
pangxianfei

现在可以了。权限控制怎么管理的。

3年前 评论
91it 3年前
Rooit 3年前

laravel-admin和jwt可以和这个一块用吗 :joy:

2年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!