Explorar o código

多后台功能

whj %!s(int64=4) %!d(string=hai) anos
pai
achega
d3fc808fab

+ 10 - 0
app/Community/Controllers/ApiController.php

xqd
@@ -0,0 +1,10 @@
+<?php
+
+
+namespace App\Community\Controllers;
+
+
+class ApiController
+{
+
+}

+ 7 - 0
storage/multitenancy/.gitignore

xqd
@@ -0,0 +1,7 @@
+.DS_Store
+phpunit.phar
+/vendor
+composer.phar
+composer.lock
+*.project
+.idea/

+ 154 - 0
storage/multitenancy/README.md

xqd
@@ -0,0 +1,154 @@
+laravel-admin multitenancy
+======
+
+在同一套laravel框架中安装多个互相独立的后台。
+
+## Installation
+
+解压之后放到`storage/multitenancy`目录下,然后打开项目根目录下的`composer.json`文件(注意:不是这个扩展包中的composer.json),增加下面的配置:
+
+```json
+    "repositories": [
+        {
+            "type": "path",
+            "url": "storage/multitenancy",
+            "options": {
+              "symlink": false
+            }
+        }
+    ]
+```
+然后运行`composer require laravel-admin-ext/multitenancy`安装它
+
+如果运行上面命令的过程中出现下面的错误:
+```bash
+[InvalidArgumentException]
+  Could not find package laravel-admin-ext/multitenancy at any version for your minimum-stability (dev). Check the package spelling or your minimum-stability
+```
+这是由于composer的最小稳定性设置不满足,建议在composer.json里面将`minimum-stability`设置为`dev`,另外`prefer-stable`设置为true, 这样给你的应用安装其它package的时候,还是会倾向于安装稳定版本, 
+composer.json的修改如下
+```json
+{
+    ...
+    "minimum-stability": "dev",
+    "prefer-stable": true,
+    ...
+}
+```
+
+
+然后运行下面的命令发布配置文件
+
+```bash
+php artisan vendor:publish --provider="Encore\Admin\Multitenancy\MultitenancyServiceProvider"
+```
+运行完成之后会生成新后台的配置文件`config/tenancy.php`, 这个文件和`config/admin.php`有一样的结构
+
+由于新建的后台需要和原后台保持隔离,所以推荐新建一个新的数据库来存放对应表,这里要创建一个新的数据库,并且在`config/database.php`中添加一个名字为`tenancy`的数据库连接
+
+> 当然数据库连接也可以是任何其它的名字,如果使用了其它的连接名,需要在`config/tenancy.php`中修改`database.connection`为相应的值。
+> 如果你不想再创建一个新的数据库来安装新的后台,打开`config/tenancy.php`,将`database`下的`connection`设置为空字符串,然后下面的表配置全部重命名掉,避免和第一个后台的这几个表冲突,建议将`admin`前缀替换即可。
+
+第二个后台将会默认安装在`app/Tenancy`目录下,如果你需要安装在其它目录,修改`config/tenancy.php`中的`directory`配置项即可,对应的`route.prefix`、`route.namespace`和`auth.controller`也要修改成对应的值。
+
+把上面生成的配置文件路径写入`config/admin.php`的`extensions`下:
+
+```php
+    'extensions' => [
+    
+        'multitenancy' => [
+            'tenancy' => config_path('tenancy.php'),
+        ]
+        
+    ]
+```
+最后运行下面的命令完成安装:
+```bash
+php artisan admin:install:tenancy
+```
+
+打开`http://localhost:8080/tenancy`访问新建的后台,这个新后台的开发工作就在`app/Tenancy`目录下了,这个后台对应的配置文件是`config/tenancy.php`,根据你的需求修改里面的配置。
+
+## 安装多个后台
+
+如果需要在这个项目中安装更多的后台,复制`config/tenancy.php`文件到config目录下,比如`config/platform.php`,然后参考上面修改里面的数据库连接
+
+因为需要安装在一个新的目录,所以同样要修改`config/platform.php`中的`directory`、`route.prefix`、`route.namespace`和`auth.controller`这几个配置项的值,
+
+然后把配置文件路径写入`config/admin.php`的`extensions`下:
+
+```php
+    'extensions' => [
+        'multitenancy' => [
+            'tenancy' => config_path('tenancy.php'),
+            
+            // 增加下面一行
+            'platform' => config_path('platform.php'),
+        ]
+    ]
+```
+
+最后运行下面的命令安装
+```bash
+php artisan admin:install:tenancy platform
+```
+如果你在`config/platform.php`设置的路由前缀是`paltform`, 那么就打开`http://localhost:8080/paltform`访问新建的后台。
+
+## session冲突问题
+
+如果你在同一个浏览器窗口打开两个后台,登入或者登出一个后台会影响到另一个后台,通过下面的方式来解决这个问题
+
+### 区分路径访问
+
+如果多个后台是通过不同的路径访问的,在每个后台的配置文件中(比如`config/admin.php`和`config/tenacy.php`)的route配置的中间件配置数据加上下面
+
+```php
+    'route' => [
+
+        'prefix' => 'tenancy',
+
+        'namespace' => 'App\\Tenancy\\Controllers',
+
+        'middleware' => ['web', 'admin', 'multi-session:path,/tenancy'],
+    ],
+```
+
+在`'multi-session:path,/tenancy'`中,`/tenancy`就是该后台的访问根路径
+
+### 区分域名访问
+
+如果多个后台是通过不同的域名访问的,分别在每个后台的配置文件中加上中间件
+
+```php
+    'route' => [
+
+        'prefix' => 'tenancy',
+
+        'namespace' => 'App\\Tenancy\\Controllers',
+
+        'middleware' => ['web', 'admin', 'multi-session:domain,admin.laravel.com'],
+    ],
+```
+
+在`'multi-session:domain,admin.laravel.com'`中,`admin.laravel.com`就是该后台的访问域名
+
+## 常见问题
+
+### 创建控制器
+
+使用`php artisan admin:make`命令创建的控制器会在原后台目录下,你可以将生成的控制器移动到当前后台的`Controllers`目录下,然后修改一下命名空间即可。
+
+如果你使用`v1.7.0`版本以上的laravel-admin, 可以加上`namespace`选项来指定生成的目录:
+
+```shell
+$ php artisan admin:make TestController --model=App\\Models\\User --title=用户管理 --namespace=App\\Tenancy\\Controllers
+```
+
+## 版本更新
+
+下载新的版本之后,从安装步骤开始,到`composer require laravel-admin-ext/multitenancy`这一步即可。
+
+## 版权声明
+
+请尊重作者知识产权, 勿传播他人使用。
+

+ 34 - 0
storage/multitenancy/composer.json

xqd
@@ -0,0 +1,34 @@
+{
+    "name": "laravel-admin-ext/multitenancy",
+    "description": "Install a new laravel-admin tenancy",
+    "type": "library",
+    "keywords": ["laravel-admin", "extension"],
+    "homepage": "https://github.com/laravel-admin-ext/multitenancy",
+    "license": "MIT",
+    "version": "v2.1.7",
+    "authors": [
+        {
+            "name": "song",
+            "email": "zosong@126.com"
+        }
+    ],
+    "require": {
+        "php": ">=7.0.0",
+        "encore/laravel-admin": "*"
+    },
+    "require-dev": {
+        "phpunit/phpunit": "~6.0"
+    },
+    "autoload": {
+        "psr-4": {
+            "Encore\\Admin\\Multitenancy\\": "src/"
+        }
+    },
+    "extra": {
+        "laravel": {
+            "providers": [
+                "Encore\\Admin\\Multitenancy\\MultitenancyServiceProvider"
+            ]
+        }
+    }
+}

+ 317 - 0
storage/multitenancy/config/tenancy.php

xqd
@@ -0,0 +1,317 @@
+<?php
+
+return [
+
+    /*
+    |--------------------------------------------------------------------------
+    | Laravel-admin name
+    |--------------------------------------------------------------------------
+    |
+    | This value is the name of laravel-admin, This setting is displayed on the
+    | login page.
+    |
+    */
+    'name' => 'Laravel-admin',
+
+    /*
+    |--------------------------------------------------------------------------
+    | Laravel-admin logo
+    |--------------------------------------------------------------------------
+    |
+    | The logo of all admin pages. You can also set it as an image by using a
+    | `img` tag, eg '<img src="http://logo-url" alt="Admin logo">'.
+    |
+    */
+    'logo' => '<b>Laravel</b> admin',
+
+    /*
+    |--------------------------------------------------------------------------
+    | Laravel-admin mini logo
+    |--------------------------------------------------------------------------
+    |
+    | The logo of all admin pages when the sidebar menu is collapsed. You can
+    | also set it as an image by using a `img` tag, eg
+    | '<img src="http://logo-url" alt="Admin logo">'.
+    |
+    */
+    'logo_mini' => '<b>La</b>',
+
+    /*
+    |--------------------------------------------------------------------------
+    | Laravel-admin route settings
+    |--------------------------------------------------------------------------
+    |
+    | The routing configuration of the admin page, including the path prefix,
+    | the controller namespace, and the default middleware. If you want to
+    | access through the root path, just set the prefix to empty string.
+    |
+    */
+    'route' => [
+
+        'prefix' => 'tenancy',
+
+        'namespace' => 'App\\Tenancy\\Controllers',
+
+        'middleware' => ['web', 'admin'],
+    ],
+
+    /*
+    |--------------------------------------------------------------------------
+    | Laravel-admin install directory
+    |--------------------------------------------------------------------------
+    |
+    | The installation directory of the controller and routing configuration
+    | files of the administration page. The default is `app/Admin`, which must
+    | be set before running `artisan admin::install` to take effect.
+    |
+    */
+    'directory' => app_path('Tenancy'),
+
+    /*
+    |--------------------------------------------------------------------------
+    | Laravel-admin html title
+    |--------------------------------------------------------------------------
+    |
+    | Html title for all pages.
+    |
+    */
+    'title' => 'Admin',
+
+    /*
+    |--------------------------------------------------------------------------
+    | Access via `https`
+    |--------------------------------------------------------------------------
+    |
+    | If your page is going to be accessed via https, set it to `true`.
+    |
+    */
+    'https' => env('ADMIN_HTTPS', false),
+
+    /*
+    |--------------------------------------------------------------------------
+    | Laravel-admin auth setting
+    |--------------------------------------------------------------------------
+    |
+    | Authentication settings for all admin pages. Include an authentication
+    | guard and a user provider setting of authentication driver.
+    |
+    | You can specify a controller for `login` `logout` and other auth routes.
+    |
+    */
+    'auth' => [
+
+        'controller' => App\Tenancy\Controllers\AuthController::class,
+
+        'guards' => [
+            'admin' => [
+                'driver'   => 'session',
+                'provider' => 'admin',
+            ],
+        ],
+
+        'providers' => [
+            'admin' => [
+                'driver' => 'eloquent',
+                'model'  => Encore\Admin\Auth\Database\Administrator::class,
+            ],
+        ],
+    ],
+
+    /*
+    |--------------------------------------------------------------------------
+    | Laravel-admin upload setting
+    |--------------------------------------------------------------------------
+    |
+    | File system configuration for form upload files and images, including
+    | disk and upload path.
+    |
+    */
+    'upload' => [
+
+        // Disk in `config/filesystem.php`.
+        'disk' => 'admin',
+
+        // Image and file upload path under the disk above.
+        'directory' => [
+            'image' => 'images',
+            'file'  => 'files',
+        ],
+    ],
+
+    /*
+    |--------------------------------------------------------------------------
+    | Laravel-admin database settings
+    |--------------------------------------------------------------------------
+    |
+    | Here are database settings for laravel-admin builtin model & tables.
+    |
+    */
+    'database' => [
+
+        // Database connection for following tables.
+        'connection' => 'tenancy',
+
+        // User tables and model.
+        'users_table' => 'admin_users',
+        'users_model' => Encore\Admin\Auth\Database\Administrator::class,
+
+        // Role table and model.
+        'roles_table' => 'admin_roles',
+        'roles_model' => Encore\Admin\Auth\Database\Role::class,
+
+        // Permission table and model.
+        'permissions_table' => 'admin_permissions',
+        'permissions_model' => Encore\Admin\Auth\Database\Permission::class,
+
+        // Menu table and model.
+        'menu_table' => 'admin_menu',
+        'menu_model' => Encore\Admin\Auth\Database\Menu::class,
+
+        // Pivot table for table above.
+        'operation_log_table'    => 'admin_operation_log',
+        'user_permissions_table' => 'admin_user_permissions',
+        'role_users_table'       => 'admin_role_users',
+        'role_permissions_table' => 'admin_role_permissions',
+        'role_menu_table'        => 'admin_role_menu',
+    ],
+
+    /*
+    |--------------------------------------------------------------------------
+    | User operation log setting
+    |--------------------------------------------------------------------------
+    |
+    | By setting this option to open or close operation log in laravel-admin.
+    |
+    */
+    'operation_log' => [
+
+        'enable' => true,
+
+        /*
+         * Only logging allowed methods in the list
+         */
+        'allowed_methods' => ['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'CONNECT', 'OPTIONS', 'TRACE', 'PATCH'],
+
+        /*
+         * Routes that will not log to database.
+         *
+         * All method to path like: admin/auth/logs
+         * or specific method to path like: get:admin/auth/logs.
+         */
+        'except' => [
+            'admin/auth/logs*',
+        ],
+    ],
+
+    /*
+    |--------------------------------------------------------------------------
+    | Admin map field provider
+    |--------------------------------------------------------------------------
+    |
+    | Supported: "tencent", "google", "yandex".
+    |
+    */
+    'map_provider' => 'google',
+
+    /*
+    |--------------------------------------------------------------------------
+    | Application Skin
+    |--------------------------------------------------------------------------
+    |
+    | This value is the skin of admin pages.
+    | @see https://adminlte.io/docs/2.4/layout
+    |
+    | Supported:
+    |    "skin-blue", "skin-blue-light", "skin-yellow", "skin-yellow-light",
+    |    "skin-green", "skin-green-light", "skin-purple", "skin-purple-light",
+    |    "skin-red", "skin-red-light", "skin-black", "skin-black-light".
+    |
+    */
+    'skin' => 'skin-blue-light',
+
+    /*
+    |--------------------------------------------------------------------------
+    | Application layout
+    |--------------------------------------------------------------------------
+    |
+    | This value is the layout of admin pages.
+    | @see https://adminlte.io/docs/2.4/layout
+    |
+    | Supported: "fixed", "layout-boxed", "layout-top-nav", "sidebar-collapse",
+    | "sidebar-mini".
+    |
+    */
+    'layout' => ['sidebar-mini', 'sidebar-collapse'],
+
+    /*
+    |--------------------------------------------------------------------------
+    | Login page background image
+    |--------------------------------------------------------------------------
+    |
+    | This value is used to set the background image of login page.
+    |
+    */
+    'login_background_image' => '',
+
+    /*
+    |--------------------------------------------------------------------------
+    | Show version at footer
+    |--------------------------------------------------------------------------
+    |
+    | Whether to display the version number of laravel-admim at the footer of
+    | each page
+    |
+    */
+    'show_version' => true,
+
+    /*
+    |--------------------------------------------------------------------------
+    | Show environment at footer
+    |--------------------------------------------------------------------------
+    |
+    | Whether to display the environment at the footer of each page
+    |
+    */
+    'show_environment' => true,
+
+    /*
+    |--------------------------------------------------------------------------
+    | Menu bind to permissionsymlink
+    |--------------------------------------------------------------------------
+    |
+    | whether enable menu bind to a permission
+    */
+    'menu_bind_permission' => true,
+
+    /*
+    |--------------------------------------------------------------------------
+    | Enable default breadcrumb
+    |--------------------------------------------------------------------------
+    |
+    | Whether enable default breadcrumb for every page content.
+    */
+    'enable_default_breadcrumb' => true,
+
+    /*
+    |--------------------------------------------------------------------------
+    | Extension Directory
+    |--------------------------------------------------------------------------
+    |
+    | When you use command `php artisan admin:extend` to generate extensions,
+    | the extension files will be generated in this directory.
+    */
+    'extension_dir' => app_path('Admin/Extensions'),
+
+    /*
+    |--------------------------------------------------------------------------
+    | Settings for extensions.
+    |--------------------------------------------------------------------------
+    |
+    | You can find all available extensions here
+    | https://github.com/laravel-admin-extensions.
+    |
+    */
+    'extensions' => [
+
+    ],
+];

+ 114 - 0
storage/multitenancy/database/migrations/create_tenancy_tables.php

xqd
@@ -0,0 +1,114 @@
+<?php
+
+use Illuminate\Support\Facades\Schema;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Database\Migrations\Migration;
+
+class CreateTenancyTables extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        $connection = config('community.database.connection') ?: config('database.default');
+
+        Schema::connection($connection)->create(config('community.database.users_table'), function (Blueprint $table) {
+            $table->increments('id');
+            $table->string('username', 190)->unique();
+            $table->string('password', 60);
+            $table->string('name');
+            $table->string('avatar')->nullable();
+            $table->string('remember_token', 100)->nullable();
+            $table->timestamps();
+        });
+
+        Schema::connection($connection)->create(config('community.database.roles_table'), function (Blueprint $table) {
+            $table->increments('id');
+            $table->string('name', 50)->unique();
+            $table->string('slug', 50);
+            $table->timestamps();
+        });
+
+        Schema::connection($connection)->create(config('community.database.permissions_table'), function (Blueprint $table) {
+            $table->increments('id');
+            $table->string('name', 50)->unique();
+            $table->string('slug', 50);
+            $table->string('http_method')->nullable();
+            $table->text('http_path');
+            $table->timestamps();
+        });
+
+        Schema::connection($connection)->create(config('community.database.menu_table'), function (Blueprint $table) {
+            $table->increments('id');
+            $table->integer('parent_id')->default(0);
+            $table->integer('order')->default(0);
+            $table->string('title', 50);
+            $table->string('icon', 50);
+            $table->string('uri', 50)->nullable();
+            $table->string('permission')->nullable();
+            $table->timestamps();
+        });
+
+        Schema::connection($connection)->create(config('community.database.role_users_table'), function (Blueprint $table) {
+            $table->integer('role_id');
+            $table->integer('user_id');
+            $table->index(['role_id', 'user_id']);
+            $table->timestamps();
+        });
+
+        Schema::connection($connection)->create(config('community.database.role_permissions_table'), function (Blueprint $table) {
+            $table->integer('role_id');
+            $table->integer('permission_id');
+            $table->index(['role_id', 'permission_id']);
+            $table->timestamps();
+        });
+
+        Schema::connection($connection)->create(config('community.database.user_permissions_table'), function (Blueprint $table) {
+            $table->integer('user_id');
+            $table->integer('permission_id');
+            $table->index(['user_id', 'permission_id']);
+            $table->timestamps();
+        });
+
+        Schema::connection($connection)->create(config('community.database.role_menu_table'), function (Blueprint $table) {
+            $table->integer('role_id');
+            $table->integer('menu_id');
+            $table->index(['role_id', 'menu_id']);
+            $table->timestamps();
+        });
+
+        Schema::connection($connection)->create(config('community.database.operation_log_table'), function (Blueprint $table) {
+            $table->increments('id');
+            $table->integer('user_id');
+            $table->string('path');
+            $table->string('method', 10);
+            $table->string('ip');
+            $table->text('input');
+            $table->index('user_id');
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        $connection = config('community.database.connection') ?: config('database.default');
+
+        Schema::connection($connection)->dropIfExists(config('community.database.users_table'));
+        Schema::connection($connection)->dropIfExists(config('community.database.roles_table'));
+        Schema::connection($connection)->dropIfExists(config('community.database.permissions_table'));
+        Schema::connection($connection)->dropIfExists(config('community.database.menu_table'));
+        Schema::connection($connection)->dropIfExists(config('community.database.user_permissions_table'));
+        Schema::connection($connection)->dropIfExists(config('community.database.role_users_table'));
+        Schema::connection($connection)->dropIfExists(config('community.database.role_permissions_table'));
+        Schema::connection($connection)->dropIfExists(config('community.database.role_menu_table'));
+        Schema::connection($connection)->dropIfExists(config('community.database.operation_log_table'));
+    }
+}

+ 137 - 0
storage/multitenancy/src/Console/InstallTenancyCommand.php

xqd
@@ -0,0 +1,137 @@
+<?php
+
+namespace Encore\Admin\Multitenancy\Console;
+
+use Encore\Admin\Console\InstallCommand;
+use Illuminate\Support\Arr;
+
+class InstallTenancyCommand extends InstallCommand
+{
+    /**
+     * The console command name.
+     *
+     * @var string
+     */
+    protected $signature = 'admin:install:tenancy {name=tenancy}';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = 'Install a new tenancy of laravel-admin';
+
+    /**
+     * Execute the console command.
+     *
+     * @return void
+     */
+    public function handle()
+    {
+        $this->overrideConfig();
+
+        parent::handle();
+    }
+
+    /**
+     * Create tenancy tables and seed it.
+     *
+     * @return void
+     */
+    public function initDatabase()
+    {
+        $path = $this->createMigration();
+
+        $this->call('migrate', ['--path' => 'database/'.dirname($path)]);
+
+        $userModel = config('admin.database.users_model');
+
+        if ($userModel::count() == 0) {
+            $this->call('db:seed', ['--class' => \Encore\Admin\Auth\Database\AdminTablesSeeder::class]);
+        }
+    }
+
+    /**
+     * Override admin config with tenancy config.
+     *
+     * @return void
+     */
+    protected function overrideConfig()
+    {
+        $name = $this->argument('name');
+
+        $configFile = config("admin.extensions.multitenancy.$name");
+
+        if (empty($configFile) || !file_exists($configFile)) {
+            $this->error("Config error");
+            $this->error("    Please check your config file [config/{$name}.php]");
+            exit;
+        }
+
+        $config = require config("admin.extensions.multitenancy.$name");
+
+        config(['admin' => $config]);
+
+        config(Arr::dot(config('admin.auth', []), 'auth.'));
+    }
+
+    /**
+     * @return string
+     */
+    protected function createMigration()
+    {
+        $name = $this->argument('name');
+
+        $path = sprintf('migrations/%s/%s_create_%s_tables.php', $name, date('Y_m_d_His'), $name);
+
+        $migration = __DIR__.'/../../database/migrations/create_tenancy_tables.php';
+
+        $contents = str_replace(['tenancy', 'Tenancy'], [$name, ucfirst($name)], file_get_contents($migration));
+
+        $file = database_path($path);
+
+        $this->laravel['files']->cleanDirectory(dirname($file));
+
+        $this->laravel['files']->makeDirectory(dirname($file), 0755, true, true);
+
+        $this->laravel['files']->put($file, $contents);
+
+        $this->line('<info>Created Migration:</info> '.pathinfo($file, PATHINFO_FILENAME));
+
+        return $path;
+    }
+
+    /**
+     * Create routes file.
+     *
+     * @return void
+     */
+    protected function createRoutesFile()
+    {
+        $file = $this->directory.'/routes.php';
+
+        $contents = <<<PHP
+<?php
+
+Route::get('/', 'HomeController@index');
+
+PHP;
+        $this->laravel['files']->put($file, str_replace('DummyNamespace', config('admin.route.namespace'), $contents));
+
+        $this->line('<info>Routes file was created:</info> '.str_replace(base_path(), '', $file));
+    }
+
+    /**
+     * Get stub contents.
+     *
+     * @param string $name
+     *
+     * @return string
+     */
+    protected function getStub($name)
+    {
+        $path = base_path("vendor/encore/laravel-admin/src/Console/stubs/$name.stub");
+
+        return $this->laravel['files']->get($path);
+    }
+}

+ 15 - 0
storage/multitenancy/src/Middleware/MultiSession.php

xqd
@@ -0,0 +1,15 @@
+<?php
+
+namespace Encore\Admin\Multitenancy\Middleware;
+
+use Illuminate\Http\Request;
+
+class MultiSession
+{
+    public function handle(Request $request, \Closure $next, $key, $value)
+    {
+        config(["session.$key" => $value]);
+
+        return $next($request);
+    }
+}

+ 24 - 0
storage/multitenancy/src/Middleware/Multitenancy.php

xqd
@@ -0,0 +1,24 @@
+<?php
+
+namespace Encore\Admin\Multitenancy\Middleware;
+
+use Illuminate\Support\Arr;
+
+class Multitenancy
+{
+    public function handle($request, \Closure $next, ...$args)
+    {
+        $this->overrideConfig($args[0]);
+
+        return $next($request);
+    }
+
+    protected function overrideConfig($name)
+    {
+        $config = require config("admin.extensions.multitenancy.$name");
+
+        config(['admin' => $config]);
+
+        config(Arr::dot(config('admin.auth', []), 'auth.'));
+    }
+}

+ 110 - 0
storage/multitenancy/src/Multitenancy.php

xqd
@@ -0,0 +1,110 @@
+<?php
+
+namespace Encore\Admin\Multitenancy;
+
+use Encore\Admin\Controllers\AuthController;
+use Encore\Admin\Extension;
+use Illuminate\Support\Arr;
+
+class Multitenancy extends Extension
+{
+    /**
+     * @var string
+     */
+    public $name = 'multitenancy';
+
+    /**
+     * @var string
+     */
+    protected static $middleware = '';
+
+    /**
+     * Register a laravel-admin tenancy.
+     *
+     * @param string $name
+     * @param array $config
+     */
+    public static function register($name, array $config)
+    {
+        static::$middleware = "multitenancy:$name";
+
+        static::registerAuthRoutes($config);
+
+        static::loadTenancyRoutes($config);
+    }
+
+    /**
+     * Register auth routes for tenancy.
+     *
+     * @param array $config
+     */
+    public static function registerAuthRoutes(array $config)
+    {
+        $attributes = [
+            'domain'     => Arr::get($config, 'route.domain'),
+            'prefix'     => Arr::get($config, 'route.prefix'),
+            'middleware' => static::prependMiddleware(Arr::get($config, 'route.middleware')),
+        ];
+
+        app('router')->group($attributes, function ($router) use ($config) {
+
+            /* @var \Illuminate\Routing\Router $router */
+            $router->namespace('Encore\Admin\Controllers')->group(function ($router) {
+
+                /* @var \Illuminate\Routing\Router $router */
+                $router->resource('auth/users', 'UserController');
+                $router->resource('auth/roles', 'RoleController');
+                $router->resource('auth/permissions', 'PermissionController');
+                $router->resource('auth/menu', 'MenuController', ['except' => ['create']]);
+                $router->resource('auth/logs', 'LogController', ['only' => ['index', 'destroy']]);
+
+                $router->post('_handle_form_', 'HandleController@handleForm')->name('admin.handle-form');
+                $router->post('_handle_action_', 'HandleController@handleAction')->name('admin.handle-action');
+            });
+
+            $authController = Arr::get($config, 'auth.controller', AuthController::class);
+
+            /* @var \Illuminate\Routing\Router $router */
+            $router->get('auth/login', $authController.'@getLogin');
+            $router->post('auth/login', $authController.'@postLogin');
+            $router->get('auth/logout', $authController.'@getLogout');
+            $router->get('auth/setting', $authController.'@getSetting');
+            $router->put('auth/setting', $authController.'@putSetting');
+        });
+    }
+
+    /**
+     * Load tenancy routes.
+     *
+     * @param array $config
+     */
+    protected static function loadTenancyRoutes(array $config)
+    {
+        $routePath = ucfirst($config['directory']) . DIRECTORY_SEPARATOR . 'routes.php';
+
+        if (file_exists($routePath)) {
+            if (!app()->routesAreCached()) {
+
+                $attributes = $config['route'];
+                $attributes['middleware'] = static::prependMiddleware($attributes['middleware']);
+
+                app('router')->group($attributes, function () use ($routePath) {
+                    require $routePath;
+                });
+            }
+        }
+    }
+
+    /**
+     * Prepend a multitenancy middleware.
+     *
+     * @param array $middleware
+     * @return array
+     */
+    protected static function prependMiddleware(array $middleware) : array
+    {
+        array_unshift($middleware, static::$middleware);
+
+        return $middleware;
+    }
+}

+ 68 - 0
storage/multitenancy/src/MultitenancyServiceProvider.php

xqd
@@ -0,0 +1,68 @@
+<?php
+
+namespace Encore\Admin\Multitenancy;
+
+use Encore\Admin\Multitenancy\Console\InstallTenancyCommand;
+use Illuminate\Support\ServiceProvider;
+
+class MultitenancyServiceProvider extends ServiceProvider
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function boot(Multitenancy $extension)
+    {
+        if (!Multitenancy::boot()) {
+            return;
+        }
+
+        if ($this->app->runningInConsole()) {
+            $this->publishes([__DIR__.'/../config' => config_path()], 'laravel-admin-tenancy-config');
+        }
+
+        $this->bootMultitenancy(config('admin.extensions.multitenancy', []));
+    }
+
+    /**
+     * Bootstrap multitenancy.
+     *
+     * @param array $configs
+     */
+    protected function bootMultitenancy(array $configs)
+    {
+        foreach ($configs as $name => $config) {
+            if (file_exists($config)) {
+                Multitenancy::register($name, require $config);
+            }
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function register()
+    {
+        $this->registerCommands();
+
+        $this->registerMiddleware();
+    }
+
+    /**
+     * Register commands.
+     */
+    protected function registerCommands()
+    {
+        $this->commands([
+            InstallTenancyCommand::class,
+        ]);
+    }
+
+    /**
+     * Register route middleware.
+     */
+    protected function registerMiddleware()
+    {
+        app('router')->aliasMiddleware('multitenancy', Middleware\Multitenancy::class);
+        app('router')->aliasMiddleware('multi-session', Middleware\MultiSession::class);
+    }
+}