Laravel 5 Implement multiple Auth drivers

前端 未结 1 1209
清歌不尽
清歌不尽 2020-12-15 00:30

Synopsis

I am building a system with at least two levels of Authentication and both have separate User models and tables in the database. A quick search on google

相关标签:
1条回答
  • 2020-12-15 01:18

    Solution

    I'm assuming you have a package available to work on. My vendor namespace in this example will simply be: Example - all code snippets can be found following the instructions.

    I copied config/auth.php to config/customerauth.php and amended the settings accordingly.

    I edited the config/app.php and replaced the Illuminate\Auth\AuthServiceProvider with Example\Auth\CustomerAuthServiceProvider.

    I edited the config/app.php and replaced the Auth alias with:

    'CustomerAuth' => 'Example\Support\Facades\CustomerAuth',
    

    I then implemented the code within the package for example vendor/example/src/. I started with the ServiceProvider: Example/Auth/CustomerAuthServiceProvider.php

    <?php namespace Example\Auth;
    
    use Illuminate\Auth\AuthServiceProvider;
    use Example\Auth\CustomerAuthManager;
    use Example\Auth\SiteGuard;
    
    class CustomerAuthServiceProvider extends AuthServiceProvider
    {
        public function register()
        {
            $this->app->alias('customerauth',        'Example\Auth\CustomerAuthManager');
            $this->app->alias('customerauth.driver', 'Example\Auth\SiteGuard');
            $this->app->alias('customerauth.driver', 'Example\Contracts\Auth\SiteGuard');
    
            parent::register();
        }
    
        protected function registerAuthenticator()
        {
            $this->app->singleton('customerauth', function ($app) {
                $app['customerauth.loaded'] = true;
    
                return new CustomerAuthManager($app);
            });
    
            $this->app->singleton('customerauth.driver', function ($app) {
                return $app['customerauth']->driver();
            });
        }
    
        protected function registerUserResolver()
        {
            $this->app->bind('Illuminate\Contracts\Auth\Authenticatable', function ($app) {
                return $app['customerauth']->user();
            });
        }
    
        protected function registerRequestRebindHandler()
        {
            $this->app->rebinding('request', function ($app, $request) {
                $request->setUserResolver(function() use ($app) {
                    return $app['customerauth']->user();
                });
            });
        }
    }
    

    Then I implemented: Example/Auth/CustomerAuthManager.php

    <?php namespace Example\Auth;
    
    use Illuminate\Auth\AuthManager;
    use Illuminate\Auth\EloquentUserProvider;
    use Example\Auth\SiteGuard as Guard;
    
    class CustomerAuthManager extends AuthManager
    {
        protected function callCustomCreator($driver)
        {
            $custom = parent::callCustomCreator($driver);
    
            if ($custom instanceof Guard) return $custom;
    
            return new Guard($custom, $this->app['session.store']);
        }
    
        public function createDatabaseDriver()
        {
            $provider = $this->createDatabaseProvider();
    
            return new Guard($provider, $this->app['session.store']);
        }
    
        protected function createDatabaseProvider()
        {
            $connection = $this->app['db']->connection();
            $table = $this->app['config']['customerauth.table'];
    
            return new DatabaseUserProvider($connection, $this->app['hash'], $table);
        }
    
        public function createEloquentDriver()
        {
            $provider = $this->createEloquentProvider();
    
            return new Guard($provider, $this->app['session.store']);
        }
    
        protected function createEloquentProvider()
        {
            $model = $this->app['config']['customerauth.model'];
    
            return new EloquentUserProvider($this->app['hash'], $model);
        }
    
        public function getDefaultDriver()
        {
            return $this->app['config']['customerauth.driver'];
        }
    
        public function setDefaultDriver($name)
        {
            $this->app['config']['customerauth.driver'] = $name;
        }
    }
    

    I then implemented Example/Auth/SiteGuard.php (note the methods implemented have an additional site_ defined, this should be different for other Auth drivers):

    <?php namespace Example\Auth;
    
    use Illuminate\Auth\Guard;
    
    class SiteGuard extends Guard
    {
        public function getName()
        {
            return 'login_site_'.md5(get_class($this));
        }
    
        public function getRecallerName()
        {
            return 'remember_site_'.md5(get_class($this));
        }
    }
    

    I then implemented Example/Contracts/Auth/SiteGuard.php

    use Illuminate\Contracts\Auth\Guard;
    
    interface SiteGuard extends Guard {}
    

    Finally I implemented the Facade; Example/Support/Facades/Auth/CustomerAuth.php

    <?php namespace Example\Support\Facades;
    
    class CustomerAuth extends Facade
    {
        protected static function getFacadeAccessor()
        {
            return 'customerauth';
        }
    }
    

    A quick update, when trying to use these custom auth drivers with phpunit you may get the following error:

    Driver [CustomerAuth] not supported.
    

    You also need to implement this, the easiest solution is override the be method and also creating a trait similar to it:

    <?php namespace Example\Vendor\Testing;
    
    use Illuminate\Contracts\Auth\Authenticatable as UserContract;
    
    trait ApplicationTrait
    {
        public function be(UserContract $user, $driver = null)
        {
            $this->app['customerauth']->driver($driver)->setUser($user);
        }
    }
    
    0 讨论(0)
提交回复
热议问题