Подтвердить что ты не робот

Аутентификация с помощью двух разных таблиц

Мне нужно создать новую конфигурацию "auth" с другой таблицей и пользователями. У меня есть одна таблица для пользователей "admin" и другая таблица для обычных пользователей.

Но как я могу создать другой экземпляр Auth с другой конфигурацией?

4b9b3361

Ответ 1

Вы можете "эмулировать" новый класс Auth.

Компонент Laravel Auth - это в основном класс Illuminate\Auth\Guard, и этот класс имеет некоторые зависимости.

Итак, в основном вам нужно создать новый класс Guard и некоторые фасады...

<?php 
use Illuminate\Auth\Guard as AuthGuard;

class CilentGuard extends AuthGuard
{

    public function getName()
    {
        return 'login_' . md5('ClientAuth');
    }

    public function getRecallerName()
    {
        return 'remember_' . md5('ClientAuth');
    }
}

... добавьте ServiceProvider, чтобы инициализировать этот класс, передавая ему зависимости.

<?php 

use Illuminate\Support\ServiceProvider;
use Illuminate\Auth\EloquentUserProvider;
use Illuminate\Hashing\BcryptHasher;
use Illuminate\Auth\Reminders\PasswordBroker;
use Illuminate\Auth\Reminders\DatabaseReminderRepository;
use ClientGuard;
use ClientAuth;

class ClientServiceProvider extends ServiceProvider 
{

    public function register()
    {
        $this->registerAuth();
        $this->registerReminders();
    }

    protected function registerAuth()
    {
        $this->registerClientCrypt();
        $this->registerClientProvider();
        $this->registerClientGuard();
    }

    protected function registerClientCrypt()
    {
        $this->app['client.auth.crypt'] = $this->app->share(function($app)
        {
            return new BcryptHasher;
        });
    }

    protected function registerClientProvider()
    {
        $this->app['client.auth.provider'] = $this->app->share(function($app)
        {
            return new EloquentUserProvider(
                $app['client.auth.crypt'], 
                'Client'
            );
        });
    }

    protected function registerClientGuard()
    {
        $this->app['client.auth'] = $this->app->share(function($app)
        {
            $guard = new Guard(
                $app['client.auth.provider'], 
                $app['session.store']
            );

            $guard->setCookieJar($app['cookie']);
            return $guard;
        });
    }

    protected function registerReminders()
    {
        # DatabaseReminderRepository
        $this->registerReminderDatabaseRepository();

        # PasswordBroker
        $this->app['client.reminder'] = $this->app->share(function($app)
        {
            return new PasswordBroker(
                $app['client.reminder.repository'], 
                $app['client.auth.provider'], 
                $app['redirect'], 
                $app['mailer'], 
                'emails.client.reminder' // email template for the reminder
            );
        });
    }

    protected function registerReminderDatabaseRepository()
    {
        $this->app['client.reminder.repository'] = $this->app->share(function($app)
        {
            $connection   = $app['db']->connection();
            $table        = 'client_reminders';
            $key          = $app['config']['app.key'];

            return new DatabaseReminderRepository($connection, $table, $key);
        });
    }

    public function provides()
    {
        return array(
            'client.auth', 
            'client.auth.provider', 
            'client.auth.crypt', 
            'client.reminder.repository', 
            'client.reminder', 
        );
    }
}

В этом поставщике услуг я приведу пример создания нового компонента напоминания пароля.

Теперь вам нужно создать два новых фасада: один для аутентификации и один для напоминаний пароля.

<?php 
use Illuminate\Support\Facades\Facade;

class ClientAuth extends Facade
{

    protected static function getFacadeAccessor() 
    {
        return 'client.auth';
    }
}

и...

<?php 
use Illuminate\Support\Facades\Facade;

class ClientPassword extends Facade
{

    protected static function getFacadeAccessor() 
    {
        return 'client.reminder';
    }
}

Конечно, для напоминаний пароля вам нужно создать таблицу в базе данных, чтобы работать. В этом примере имя таблицы должно быть client_reminders, как вы можете видеть в методе registerReminderDatabaseRepository в Провайдере. Структура таблицы такая же, как и исходная таблица напоминаний.

После этого вы можете использовать ClientAuth так же, как вы используете класс Auth. И то же самое для ClientPassword с классом Password.

ClientAuth::gust();
ClientAuth::attempt(array('email' => $email, 'password' => $password));

ClientPassword::remind($credentials);

Не забудьте добавить поставщика услуг в список поставщиков услуг в файле app/config/app.php.

UPDATE:

Если вы используете Laravel 4.1, PasswordBroker больше не нуждается в классе Redirect.

return new PasswordBroker(
    $app['client.reminder.repository'], 
    $app['client.auth.provider'], 
    $app['mailer'], 
    'emails.client.reminder' // email template for the reminder
);

ОБНОВЛЕНИЕ 2

Laravel 5.2 только что представил multi auth, поэтому в этой версии больше не требуется.

Ответ 2

При попытке решить эту проблему я нашел гораздо более простой способ. В основном я создал собственный ServiceProvider для замены по умолчанию Auth one, который служит классом factory для Auth и позволяет вам иметь несколько экземпляров для нескольких типов входа. Я также застрял в пакете, который можно найти здесь: https://github.com/ollieread/multiauth

Это довольно простое использование, просто замените AuthServiceProvider в app/config/app.php с помощью Ollieread\Multiauth\MultiauthServiceProvider, а затем измените app/config/auth.php, чтобы выглядеть примерно так:

return array(

    'multi' => array(
        'account' => array(
            'driver' => 'eloquent',
            'model' => 'Account'
        ),
        'user' => array(
            'driver' => 'database',
            'table' => 'users'
        )
    ),

    'reminder' => array(

        'email' => 'emails.auth.reminder',

        'table' => 'password_reminders',

        'expire' => 60,

    ),

);

Теперь вы можете просто использовать Auth так же, как и раньше, но с небольшим разницей:

Auth::account()->attempt(array(
    'email'     => $attributes['email'],
    'password'  => $attributes['password'],
));
Auth::user()->attempt(array(
    'email'     => $attributes['email'],
    'password'  => $attributes['password'],
));
Auth::account()->check();
Auth::user()->check();

Он также позволяет вам регистрироваться как несколько типов пользователей одновременно, что является требованием для проекта, над которым я работал. Надеюсь, это поможет кому-то, кроме меня.

ОБНОВЛЕНИЕ - 27/02/2014

Для тех из вас, кто просто встречает этот ответ, я недавно добавил поддержку напоминаний, к которым можно получить доступ в том же стиле factory.

Ответ 3

Хорошо, у меня была та же проблема, и вот как я ее решил:

На самом деле в laravel 4 вы можете просто изменить конфигурацию auth во время выполнения, поэтому, чтобы сделать трюк, вы можете просто сделать следующее в своем приложении:: before filter:

if ($request->is('admin*'))
{
    Config::set('auth.model', 'Admin');
}

это заставит компонент Auth использовать модель администратора, когда в URL-адресах администратора. но это приведет к возникновению новой проблемы, поскольку ключ сеанса входа будет таким же, если у вас есть два пользователя в вашей группе администраторов и пользователей с тем же идентификатором, который вы сможете войти на сайт администратора, если вы вошли в систему раньше, как обычный пользователь! поэтому для того, чтобы сделать две разные авторизации совершенно независимыми, я сделал этот трюк:

class AdminGuard extends Guard
{
    public function getName()
    {
        return 'admin_login_'.md5(get_class($this));
    }

    public function getRecallerName()
    {
        return 'admin_remember_'.md5(get_class($this));
    }
}

Auth::extend('eloquent.admin', function()
{
    return new AdminGuard(new EloquentUserProvider(new BcryptHasher, 'Admin'), App::make('session.store'));
});

и измените код приложения:: перед кодом:

if ($request->is('admin*'))
{
    Config::set('auth.driver', 'eloquent.admin');
    Config::set('auth.model', 'Admin');
}

вы можете видеть, что я создал новый драйвер auth и переписал некоторые методы в классе Guard, чтобы он генерировал разные ключи сеанса для сайта администратора. затем я изменил драйвер для сайта администратора. удачи.

Ответ 4

У меня была такая же проблема вчера, и я создал гораздо более простое решение.

Мои требования, когда две разные таблицы в двух разных базах данных. Один стол был для админов, другой для обычных пользователей. Кроме того, каждая таблица имела свой собственный способ хэширования. В итоге я получил следующее (код также доступен как gist на Github: https://gist.github.com/Xethron/6790029)

Создайте новый UserProvider. Я назвал мой MultiUserProvider.php

<?php

// app/libraries/MultiUserProvider.php

use Illuminate\Auth\UserProviderInterface,
    Illuminate\Auth\UserInterface,
    Illuminate\Auth\GenericUser;

class MultiUserProvider implements UserProviderInterface {

  protected $providers;

    public function __construct() {

        // This should be moved to the config later...
        // This is a list of providers that can be used, including
        // their user model, hasher class, and hasher options...
        $this->providers = array(
            'joomla' => array(
                'model' => 'JoomlaUser',
                'hasher' => 'JoomlaHasher',
                )
            'another' => array(
                'model' => 'AnotherUser',
                'hasher' => 'AnotherHasher',
                'options' => array(
                    'username' => 'empolyee_number',
                    'salt' => 'salt',
                    )
                ),
            );
    }
    /**
     * Retrieve a user by their unique identifier.
     *
     * @param  mixed  $identifier
     * @return \Illuminate\Auth\UserInterface|null
     */
    public function retrieveById($identifier)
    {
        // Returns the current provider from the session.
        // Should throw an error if there is none...
        $provider = Session::get('user.provider');

        $user = $this->createModel($this->providers[$provider]['model'])->newQuery()->find($identifier);

        if ($user){
            $user->provider = $provider;
        }

        return $user;
    }

    /**
     * Retrieve a user by the given credentials.
     *
     * @param  array  $credentials
     * @return \Illuminate\Auth\UserInterface|null
     */
    public function retrieveByCredentials(array $credentials)
    {
        // First we will add each credential element to the query as a where clause.
        // Then we can execute the query and, if we found a user, return it in a
        // Eloquent User "model" that will be utilized by the Guard instances.

        // Retrieve the provider from the $credentials array.
        // Should throw an error if there is none...
        $provider = $credentials['provider'];

        $query = $this->createModel($this->providers[$provider]['model'])->newQuery();

        foreach ($credentials as $key => $value)
        {
            if ( ! str_contains($key, 'password') && ! str_contains($key, 'provider'))
                $query->where($key, $value);
        }

        $user = $query->first();

        if ($user){
            Session::put('user.provider', $provider);
            $user->provider = $provider;
        }

        return $user;
    }

    /**
     * Validate a user against the given credentials.
     *
     * @param  \Illuminate\Auth\UserInterface  $user
     * @param  array  $credentials
     * @return bool
     */
    public function validateCredentials(UserInterface $user, array $credentials)
    {
        $plain = $credentials['password'];

        // Retrieve the provider from the $credentials array.
        // Should throw an error if there is none...
        $provider = $credentials['provider'];

        $options = array();

        if (isset($this->providers[$provider]['options'])){
            foreach ($this->providers[$provider]['options'] as $key => $value) {
                $options[$key] = $user->$value;
            }
        }

        return $this->createModel($this->providers[$provider]['hasher'])
            ->check($plain, $user->getAuthPassword(), $options);
    }

    /**
     * Create a new instance of a class.
     *
     * @param string $name Name of the class
     * @return Class
     */
    public function createModel($name)
    {
        $class = '\\'.ltrim($name, '\\');

        return new $class;
    }

}

Затем я рассказал Laravel о моем UserProvider, добавив следующие строки в начало моего файла app/start/global.php.

// app/start/global.php

// Add the following few lines to your global.php file
Auth::extend('multi', function($app) {
    $provider =  new \MultiUserProvider();

    return new \Illuminate\Auth\Guard($provider, $app['session']);
});

И затем я сказал Laravel использовать мой провайдер вместо EloquentUserProvider в app/config/auth.php

'driver' => 'multi',

Теперь, когда я аутентифицируюсь, я делаю это так:

Auth::attempt(array(
    'email' => $email,
    'password' => $password,
    'provider'=>'joomla'
    )
)

Затем класс будет использовать модель joomlaUser с помощью joomlaHasher и без параметров для хэширования... Если использовать "другого" провайдера, он будет включать опции для хэширования.

Этот класс был создан для того, что мне нужно, но его можно легко изменить, чтобы удовлетворить ваши потребности.

PS: Убедитесь, что автозагрузчик может найти MultiUserProvider, иначе он не будет работать.

Ответ 5

Я использую autor Laravel 5 для обработки нескольких пользовательских таблиц...

Это не сложно, пожалуйста, проверьте этот Gist:

https://gist.github.com/danielcoimbra/64b779b4d9e522bc3373

UPDATE: для Laravel 5, если вам нужно более надежное решение, попробуйте этот пакет:

https://github.com/sboo/multiauth

Daniel