定制 worldesports/laravel-auto-tenancy 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

worldesports/laravel-auto-tenancy

Composer 安装命令:

composer require worldesports/laravel-auto-tenancy

包简介

Laravel package for post-authentication multi-tenancy with per-tenant database isolation and automatic connection switching

README 文档

README

Post-authentication multi-tenancy for Laravel applications with runtime tenant connection resolution and automatic database switching after login.

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status PHPStan Total Downloads

What makes this package different?

Most Laravel multi-tenancy packages are commonly used in domain-first or subdomain-first workflows, where the tenant is identified from the request before or independently of user authentication.

worldesports/laravel-auto-tenancy is built for a different workflow:

  1. The user logs in or registers first.
  2. The application determines the tenant from the authenticated user.
  3. The package chooses or builds the correct database connection at runtime for that tenant.
  4. The application is automatically switched into the correct tenant database/context.

This makes it a strong fit for Laravel applications where tenancy is resolved after authentication rather than solely from the incoming request host.

Example use case

Your app has a shared login screen for all users.

After authentication:

  • user ID 1 should use the tenant/database provisioned for user ID 1
  • user ID 2 should use the tenant/database provisioned for user ID 2
  • tenant context is determined from the authenticated user by default
  • the package switches the application into the correct tenant database/context

Good Fit for This Package

Use this package if your app needs to:

  • resolve tenancy after login or registration
  • determine the tenant from the authenticated user
  • choose or build the correct tenant database connection at runtime
  • switch tenant databases automatically
  • add tenancy to an existing Laravel auth flow without redesigning the app around domain-first tenancy
  • integrate with existing multi-tenant systems

When This May Not Be the Right Fit

If your application is primarily domain-first or subdomain-first and you need broader tenant bootstrapping beyond authenticated-user-driven database switching, another tenancy approach may be a better fit.

Features

  • Post-authentication multi-tenancy: Tenants are automatically detected and switched after user login
  • Runtime connection resolution: The package chooses or builds the correct tenant connection for the authenticated user
  • Multiple database support: Each tenant can use a separate database connection
  • Minimal configuration: Install quickly with sensible defaults
  • Automatic tenant switching: Middleware automatically resolves and switches tenant context
  • Model scoping: Traits for tenant-aware model queries
  • Database isolation: Complete separation between tenant data
  • Multi-driver support: MySQL, PostgreSQL, SQLite, and SQL Server
  • Connection caching: Optimized database connection management
  • Encryption support: Optional encryption for sensitive connection details
  • Comprehensive commands: Full set of Artisan commands for tenant management
  • Event listeners: Automatic tenant creation and cleanup
  • Security features: Access control and validation
  • Testing suite: Comprehensive test coverage

Installation

You can install the package via composer:

composer require worldesports/laravel-auto-tenancy

Quick installation with setup:

php artisan tenant:install --force --migrate

If authentication is missing, the installer will prompt you to install Jetstream:

composer require laravel/jetstream
php artisan jetstream:install livewire
npm install && npm run build
php artisan migrate

Or manual installation:

# Publish and run the migrations
php artisan vendor:publish --tag="multi-tenancy-migrations"
php artisan migrate

# Optionally, publish the config file
php artisan vendor:publish --tag="multi-tenancy-config"

The published config file (config/multi-tenancy.php) contains:

<?php

return [
    // Your User model
    'user_model' => App\\Models\\User::class,
    
    // Main database connection
    'main_connection' => config('database.default', 'mysql'),
    
    // Auto-create tenant on user registration (optional)
    'auto_create_tenant' => false,

    // Optional email-domain detection; disabled by default for security
    'auto_detect_by_email' => false,
    
    // Performance optimizations
    'cache_connections' => true,
    
    // Security features
    'encrypt_connection_details' => false,
    
    // ... more options
];

Basic Usage

1. User Model Configuration

The package automatically works with your existing User model. If you're using a custom User model or different namespace:

// In config/multi-tenancy.php
'user_model' => App\Models\CustomUser::class,

2. Authentication System Compatibility

Laravel Breeze

# Standard Laravel Breeze setup
composer require laravel/breeze
php artisan breeze:install
npm install && npm run dev
php artisan migrate

# Then install multi-tenancy
composer require worldesports/laravel-auto-tenancy
php artisan tenant:install --migrate

Laravel Jetstream

# Standard Jetstream setup
composer require laravel/jetstream
php artisan jetstream:install livewire
npm install && npm run build
php artisan migrate

# Then install multi-tenancy
composer require worldesports/laravel-auto-tenancy
php artisan tenant:install --migrate

Laravel Sanctum API

# For API-based applications
composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate

# Then install multi-tenancy
composer require worldesports/laravel-auto-tenancy
php artisan tenant:install --migrate

Social Authentication

# With Laravel Socialite
composer require laravel/socialite
# Configure OAuth providers in config/services.php

# Then install multi-tenancy
composer require worldesports/laravel-auto-tenancy
php artisan tenant:install --migrate

Setup and Usage

1. Register the middleware (optional)

If you want to manually control when tenant switching happens, add the middleware to your routes:

// In routes/web.php or routes/api.php
Route::middleware(['auth', 'tenant'])->group(function () {
    // Your tenant-aware routes here
});

2. Add traits to your models

For models that should be automatically scoped to the current tenant database:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Worldesports\MultiTenancy\Traits\BelongsToTenant;

class Post extends Model
{
    use BelongsToTenant; // Automatically uses tenant database
    
    // Your model code...
}

For models that have a tenant_id column and need tenant-based scoping:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Worldesports\MultiTenancy\Traits\TenantScoped;

class Document extends Model
{
    use TenantScoped; // Automatically scopes by tenant_id
    
    protected $fillable = ['title', 'content', 'tenant_id'];
}

Usage

Package Status and Management

# Show overall status
php artisan tenant:status

# Show detailed tenant list
php artisan tenant:status --list

# Show specific tenant details
php artisan tenant:status --tenant=1

# Test all database connections
php artisan tenant:status --connections

# Test connections for one driver only
php artisan tenant:status --connections --driver=mysql
php artisan tenant:status --connections --driver=pgsql
php artisan tenant:status --connections --driver=sqlite
php artisan tenant:status --connections --driver=sqlsrv

Creating Tenants

Use the artisan command to create a new tenant. The package supports all major database drivers:

MySQL Tenant (Default)

php artisan tenant:create 1 "MySQL Company" \
  --db-name=tenant_mysql_db \
  --db-driver=mysql \
  --db-host=127.0.0.1 \
  --db-port=3306 \
  --db-username=mysql_user \
  --db-password=secret \
  --create-db

PostgreSQL Tenant

php artisan tenant:create 2 "PostgreSQL Company" \
  --db-name=tenant_postgres_db \
  --db-driver=pgsql \
  --db-host=127.0.0.1 \
  --db-port=5432 \
  --db-username=postgres_user \
  --db-password=secret \
  --create-db

SQLite Tenant

php artisan tenant:create 3 "SQLite Company" \
  --db-name=/path/to/tenant.sqlite \
  --db-driver=sqlite
  # Note: SQLite doesn't need username/password/host/port

SQL Server Tenant

php artisan tenant:create 4 "SQL Server Company" \
  --db-name=tenant_sqlserver_db \
  --db-driver=sqlsrv \
  --db-host=127.0.0.1 \
  --db-port=1433 \
  --db-username=sa \
  --db-password=secret \
  --create-db

Multi-Driver Support

Your Laravel application can have tenants using different database drivers simultaneously:

  • Tenant 1: Uses MySQL on server A
  • Tenant 2: Uses PostgreSQL on server B
  • Tenant 3: Uses SQLite local file
  • Tenant 4: Uses SQL Server on server C

The package automatically handles driver-specific configurations and optimizations.

Database Management

# Run migrations on all tenant databases
php artisan tenant:migrate

# Run migrations on specific tenant
php artisan tenant:migrate --tenant=1

# Run migrations on specific database
php artisan tenant:migrate --database=1

# Fresh migrations with seeding
php artisan tenant:migrate --fresh --seed

# Seed tenant databases
php artisan tenant:seed

# Seed with specific seeder
php artisan tenant:seed --class=UserSeeder

# Test all tenant database connections
php artisan tenant:status --connections

# Test connections for one driver only
php artisan tenant:status --connections --driver=mysql
php artisan tenant:status --connections --driver=pgsql
php artisan tenant:status --connections --driver=sqlite
php artisan tenant:status --connections --driver=sqlsrv

Tenant Cleanup

# Cleanup tenant (keeps database)
php artisan tenant:cleanup 1

# Cleanup and drop database (DANGEROUS!)
php artisan tenant:cleanup 1 --drop-database

# Skip confirmation
php artisan tenant:cleanup 1 --drop-database --force

Working with Tenants in Code

use Worldesports\MultiTenancy\Facades\MultiTenancy;
use Worldesports\MultiTenancy\Models\Tenant;
use Worldesports\MultiTenancy\Models\TenantDatabase;

// Get current tenant
$tenant = MultiTenancy::getTenant();

// Manually set a tenant
$tenant = Tenant::find(1);
MultiTenancy::setTenant($tenant);

// Manually set a tenant and pick a specific tenant database
$database = TenantDatabase::find(5);
MultiTenancy::useDatabase($database); // switches default connection to this DB

// Or pass a database ID when setting the tenant (falls back to primary/first if null)
MultiTenancy::setTenant($tenant, $databaseId = 5);

// Check if tenant is set
if (MultiTenancy::hasTenant()) {
    // Tenant is active, queries will use tenant database
}

// Switch back to main connection
MultiTenancy::switchToMainConnection();

// Reset tenant context completely
MultiTenancy::resetTenant();

// Purge all cached connections
MultiTenancy::purgeConnections();

Querying for a specific tenant (and database) without changing the global context

// Scope a model to a tenant (uses its primary DB)
Invoice::forTenant($tenantId = 10)->get();

// Scope a model to a specific tenant *database* without switching the app default
Invoice::forTenant($tenantId = 10, $databaseId = 22)->get();

Note: The package keeps one active tenant database at a time per request/context. You can pick which tenant DB to use, but queries execute against a single selected database, not multiple concurrently.

Tenant Resolution

By default, the package resolves tenants after authentication by matching the authenticated user's primary key to tenants.user_id. That is the recommended production path because it does not trust hostnames or email domains for tenant membership.

php artisan tenant:create 123 "Manual Tenant"

When user ID 123 logs in and the tenant middleware runs, the package loads that user's tenant, builds the tenant database connection from the stored tenant_databases.connection_details, and switches the request to that connection.

Optional Strategy: Email Domain Detection

Email-domain detection is available, but it is disabled by default. Enable it only if your application treats matching email domains as authorized tenant membership:

# Create tenant for a company
php artisan tenant:create 1 "ACME Corporation" --domain=acme.com

Configuration:

'auto_detect_by_email' => true,

Also enable domain-based access if non-owner users should be authorized by exact email-domain match:

'security' => [
    'allow_email_domain_access' => true,
],

Optional Strategy: Subdomain Detection

Subdomain detection is available, but disabled by default and should be paired with Laravel trusted-host protection:

# Create tenant with subdomain
php artisan tenant:create 2 "Client Portal" --subdomain=client1

Configuration:

'subdomain' => [
    'enabled' => true,
    'base_domain' => 'example.com',
],

Optional Strategy: Auto-Create Tenants

Auto-create is disabled by default. For production v1 usage, prefer tenant:create because it explicitly provisions the tenant database credentials used for runtime switching:

php artisan tenant:create 123 "Manual Tenant"

Configuration:

'auto_create_tenant' => true,

tenant:create remains the provisioning path for database credentials. Runtime requests do not use root/admin credentials.

Using the Middleware

The SetTenant middleware resolves tenant context for authenticated users. It is non-enforcing by default; use tenant.required on routes that must have tenant context.

// Apply the tenant middleware after auth on routes that should resolve tenant context
Route::middleware(['auth', \Worldesports\MultiTenancy\Middleware\SetTenant::class])
    ->get('/dashboard', [DashboardController::class, 'index']);

// With error handling options
Route::middleware(['auth', \Worldesports\MultiTenancy\Middleware\SetTenant::class . ':error'])
    ->get('/api/data', [ApiController::class, 'index']);

// Require a tenant to be present (403s if missing)
Route::middleware(['auth', 'tenant', 'tenant.required'])
    ->group(function () {
        Route::get('/account', [AccountController::class, 'show']);
    });

Middleware options:

  • ignore (default): Continue when no tenant exists
  • error: Return JSON error response when no tenant exists
  • redirect: Redirect to multi-tenancy.tenant_setup_route when configured

Advanced Configuration

Common Configuration

After publishing config/multi-tenancy.php, common production settings include:

'auto_create_tenant' => false,

'auto_detect_by_email' => false,

'subdomain' => [
    'enabled' => false,
    'base_domain' => null,
],

'tenant_migrations_path' => database_path('migrations/tenant'),

'cache_connections' => true,

'encrypt_connection_password' => true,

'security' => [
    'check_user_tenant_access' => true,
    'allow_email_domain_access' => false,
],

Event Listeners

The package automatically registers these event listeners:

// Auto-set tenant on user login
Event::listen(Login::class, SetTenantOnLogin::class);

// Auto-create tenant on user registration (optional)
Event::listen(Registered::class, CreateTenantOnRegistration::class);

Security Features

// Check if user has access to tenant
if (!MultiTenancy::userHasAccessToTenant($user, $tenant)) {
    throw new UnauthorizedException('Access denied');
}

// Sanitized connection details (excludes sensitive info)
$safeDetails = $tenantDatabase->safe_connection_details;

Model Scoping Examples

// Using BelongsToTenant trait
class Invoice extends Model
{
    use BelongsToTenant;
    
    // Automatically queries tenant database
    public static function recent()
    {
        return static::where('created_at', '>', now()->subDays(30))->get();
    }
}

// Using TenantScoped trait (for models with tenant_id)
class Order extends Model
{
    use TenantScoped;
    
    // Automatically scoped to current tenant
    public function scopeUnpaid($query)
    {
        return $query->where('paid', false);
    }
    
    // Bypass tenant scoping when needed
    public static function allTenantsOrders()
    {
        return static::withoutTenantScoping()->get();
    }
}

Multi-User & Concurrent Session Support

✅ Multiple Users, Different Tenants

Each authenticated request resolves its own tenant context:

// User A logs in → uses the tenant database provisioned for User A
// User B logs in → uses the tenant database provisioned for User B
// User C logs in → uses the tenant database provisioned for User C

// All three users can be using the app simultaneously with different tenant databases!

✅ Request Isolation

  • Each request receives a fresh tenant context from the authenticated user
  • No interference between concurrent users
  • Tenant context is reset after the request to support long-lived workers
  • Use the tenant middleware on authenticated web/API routes that need tenant data

✅ API & Web Support

// Web users (sessions)
Route::middleware(['auth:web', SetTenant::class])->group(function () {
    // Each web session gets its tenant context
});

// API users (tokens) 
Route::middleware(['auth:sanctum', SetTenant::class])->group(function () {
    // Each API request gets tenant context based on the authenticated user
});

Example 1: Social Media Authentication with Multi-Tenancy

// In your SocialAuthController (using Laravel Socialite)
class SocialAuthController extends Controller
{
    public function redirectToProvider($provider)
    {
        return Socialite::driver($provider)->redirect();
    }

    public function handleProviderCallback($provider)
    {
        $socialUser = Socialite::driver($provider)->user();
        
        // Find or create user
        $user = User::firstOrCreate(
            ['email' => $socialUser->getEmail()],
            [
                'name' => $socialUser->getName(),
                'password' => bcrypt(Str::random(16)), // Random password for social users
            ]
        );

        // Log the user in
        Auth::login($user);
        
        // The login listener can set tenant context for this request.
        // Keep the tenant middleware on authenticated routes for later requests.
        
        return redirect()->intended('/dashboard');
    }
}

Example 2: API Authentication with Sanctum

// API route with post-auth tenant switching
Route::middleware(['auth:sanctum', 'tenant'])->group(function () {
    // The tenant middleware applies tenant context for the authenticated user
    Route::get('/api/tenant-data', function (Request $request) {
        // All queries automatically use the user's tenant database
        $data = SomeModel::all(); // Automatically scoped to tenant
        return response()->json($data);
    });
});

// Add tenant.required to routes that must fail closed when no tenant exists.

Example 3: Custom Authentication Guard

// If using custom authentication guard
'guards' => [
    'custom' => [
        'driver' => 'session',
        'provider' => 'custom_users',
    ],
],

'providers' => [
    'custom_users' => [
        'driver' => 'eloquent',
        'model' => App\Models\CustomUser::class,
    ],
],

// In your config/multi-tenancy.php
'user_model' => App\Models\CustomUser::class,

// The package works automatically with any authentication guard!

Example 4: Multi-Guard Authentication

// For applications with multiple user types (admin, customer, etc.)
Route::middleware(['auth:web'])->group(function () {
    // Add 'tenant' to regular customer routes that need tenant context
});

Route::middleware(['auth:admin'])->group(function () {
    // Admin routes - can bypass tenant scoping when needed
    Route::get('/admin/all-tenants', function () {
        return Tenant::withoutGlobalScopes()->get(); // See all tenants
    });
});

Example 5: Automated Tenant Creation for New Users

// Enable auto-tenant creation in config/multi-tenancy.php
'auto_create_tenant' => true,

// When this optional listener is enabled, newly registered users get a tenant row:
// - Social media registration
// - Email/password registration  
// - API registration
// - SSO registration
// - Any custom registration flow
//
// Production apps should still provision tenant database credentials with tenant:create.

Testing

composer test

Changelog

Please see CHANGELOG for more information on what has changed recently.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

Credits

License

The MIT License (MIT). Please see License File for more information.

worldesports/laravel-auto-tenancy 适用场景与选型建议

worldesports/laravel-auto-tenancy 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 0 次下载、GitHub Stars 达 32, 最近一次更新时间为 2026 年 03 月 30 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「laravel」 「multi-tenant」 「zero-config」 「auto-tenancy」 「post-authentication」 「database-switching」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 worldesports/laravel-auto-tenancy 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 worldesports/laravel-auto-tenancy 我们能提供哪些服务?
定制开发 / 二次开发

基于 worldesports/laravel-auto-tenancy 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 33
  • 点击次数: 29
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 32
  • Watchers: 0
  • Forks: 1
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-03-30