Search code examples
laravelauthenticationmulti-tenant

How to login to a different database and continue working with default one?


Imagine you have this inside .env file:

DB_CONNECTION=global
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=global
DB_USERNAME=dbuser
DB_PASSWORD=password

And you have one more connection inside config/database.php called tenant.

Now when I try to log in I switch the connection to tenant and I use the username and password from that database, I can log in, log out and all works fine.

But now I want to be able to log in with a user that doesn't exist in this tenant DB.

I started to overwrite the login() function like this:

Tip: remember that at this point the connection is set to tenant!

public function login(Request $request)
{

    $parts = explode(':', $request['username']);

    if ($parts[0] === 'global') {
        \DB::purge(\DB::getDatabaseName());
        \DB::reconnect('global');

        \Schema::connection('global')->getConnection()->reconnect();
    }
   ::::::::::::::::::

But this doesn't work... It doesn't switch the connection

I want to log in with a user from global DB and continue to work with tenant DB...

Is this even possible?


Update:

I already solved the part of how to switch the DB connection... The problem is only authentication to a different one!


Solution

  • To avoid having to play with the default database connection, you should create two different model per database authenticatable user with each one its own $connection declared on the model

    class UserGlobal extends User
    {
        protected $connection = 'global';
    }
    
    class UserTennant extends User
    {
        protected $connection = 'tennant';
    }
    

    You will need to do multi-authentification middlewares or use laravel's auth using this guide laravel simple multi-auth to have an idea.

    // config/auth.php
    
        <?php
    
        [...]
        'guards' => [
            [...]
            'global' => [
                'driver' => 'session',
                'provider' => 'globals',
            ],
            'tennant' => [
                'driver' => 'session',
                'provider' => 'tennants',
            ],
        ],
    
        [...]
        'providers' => [
            [...]
            'globals' => [
                'driver' => 'eloquent',
                'model' => App\UserGlobal::class,
            ],
            'tennants' => [
                'driver' => 'eloquent',
                'model' => App\UserTennant::class,
            ],
        ],
    

    You need also to declare both database connection in config/database.php

    'connections' => [
        'global' => [
                'driver' => 'mysql',
                'host' => env('DB_HOST_GLOBAL', '127.0.0.1'),
                ...
                ],
        'tennant' => [
                'driver' => 'mysql',
                'host' => env('DB_HOST_TENNANT', '127.0.0.1'),
                ...
                ],
        ]
    

    What login would look like

    public function login(Request $request)
    {
        $tennant= $this->loginGuard($request->get('email'), $request->get('password'), auth('tennant'));
        $global= $this->loginGuard($request->get('email'), $request->get('password'), auth('global'));
        if (!$tennant && !$global) {
            return 'wrong credential';
        }
        return 'welcome';
    }
    
    private function loginGuard($email, $password, $guard)
    {
        $token = $guard->attempt(['email' => $email, 'password' => $password]);
        if (!$token || !$guard->user()->isLoggingIn()) {
            return null;
        }
        return $guard->user();
    }