Laravel応用 複数の認証クラスを利用

Posted: 2014-10-12 23:11 |  laravel 

Laravel4.2の話ですが、

Authクラスって一般ユーザーと管理者とか別々のテーブルで分けたいんだけどどーするの?

Laravelレシピ日本語版で載せるかどうか迷ったんですが、
そのうち載せるかもしれないですが、
たまに聞かれるので、おそらく最もベーシックな方法(だと思っている)を紹介します
別々のテーブルじゃなくても、1テーブルでも構いませんが、
DB設計的にも明らかに用途が違うユーザーが1テーブルにまとめてある設計は、恐らく無い と思いますが
そのパターンでもかまいません
特に難しい事はありません、ソース読んで拡張するだけです。

では

一般のユーザーの認証はデフォルトで用意されているドライバーのEloquentを利用したとします

namespace App\Repositories\Eloquent;

use Illuminate\Auth\UserTrait;
use Illuminate\Auth\UserInterface;
use Illuminate\Database\Eloquent\Model as Eloquent;
use Illuminate\Auth\Reminders\RemindableTrait;
use Illuminate\Auth\Reminders\RemindableInterface;

/**
 * Class User
 * @package App\Repositories\Eloquent
 */
class User extends Eloquent implements UserInterface, RemindableInterface
{

    use UserTrait, RemindableTrait;

    /**
     * The database table used by the model.
     *
     * @var string
     */
    protected $table = 'users';

    /**
     * The attributes excluded from the model's JSON form.
     *
     * @var array
     */
    protected $hidden = ['password', 'remember_token'];

}

そのままです
自分はPSR-4で開発しているため名前空間を利用しています
configは次の様になりますね

return [

    'driver' => 'eloquent',

    'model' => 'App\Repositories\Eloquent\User',

(一部抜粋)
次に管理者用のドライバーを用意します
ここではQueryBuilerを利用して、
管理者テーブルに合わせてカラム名等を変更する場合は任意で変更します
ここでは管理者ユーザー検索に利用するテーブルを"administorators"、
管理者を特定するユニークキーを"administorator_id"とします
かつパスワードはmd5です
Illuminate\Auth\EloquentUserProviderやIlluminate\Auth\DatabaseUserProviderを見るとわかりますが、
Illuminate\Auth\UserProviderInterface を利用しなければなりません

用途に合わせて用意します

namespace App\Authenticate;

use Illuminate\Auth\UserInterface;
use Illuminate\Auth\UserProviderInterface;

/**
 * Class AdminUserProvider
 * @package App\Authenticate
 */
class AdminUserProvider implements UserProviderInterface
{

    /**
     * The table containing the users.
     * @var string
     */
    protected $table = "administrators";

    /**
     * @param  mixed  $identifier
     * @return \Illuminate\Auth\UserInterface|null
     */
    public function retrieveById($identifier)
    {
        $user = \DB::connection('slave')
            ->table($this->table)->find($identifier);
        if (!is_null($user)){
            return new AdminUser((array) $user);
        }
    }

    /**
     * @param  mixed   $identifier
     * @param  string  $token
     * @return \Illuminate\Auth\UserInterface|null
     */
    public function retrieveByToken($identifier, $token)
    {
        $user = \DB::connection('slave')->table($this->table)
            ->where('administrator_id', $identifier)
            ->where('remember_token', $token)
            ->first();
        if(!is_null($user))
        {
            return new AdminUser((array) $user);
        }
    }

    /**
     * @param  \Illuminate\Auth\UserInterface  $user
     * @param  string  $token
     * @return void
     */
    public function updateRememberToken(UserInterface $user, $token)
    {
        \DB::connection('slave')->table($this->table)
            ->where('id', $user->getAuthIdentifier())
            ->update(
                [
                    'remember_token' => $token
                ]
            );
    }

    /**
     * @param  array  $credentials
     * @return \Illuminate\Auth\UserInterface|null
     */
    public function retrieveByCredentials(array $credentials)
    {
        $query = \DB::connection('slave')->table($this->table);
        foreach ($credentials as $key => $value) {
            if (!str_contains($key, 'password')) {
                $query->where($key, $value);
            }
        }
        $user = $query->first();
        if (!is_null($user)) {
            return new AdminUser((array) $user);
        }
    }

    /**
     * @param  \Illuminate\Auth\UserInterface  $user
     * @param  array  $credentials
     * @return bool
     */
    public function validateCredentials(UserInterface $user, array $credentials)
    {
        $plain = $credentials['password'];
        return (md5($plain) == $user->getAuthPassword());
    }
}
QueryBuilderを利用して、接続先はslaveでパスワードはデフォルトのHashからmd5へ変更しました
teratail Laravel 4の認証でHash::make()の代わりにmd5を使う方法 で書きましたが、
これらのドライバーはIlluminate\Auth\Guard で利用されます
定められたインターフェースを利用する事で意図するままに変更できます
これらの処理で利用されるデータは Illuminate\Auth\UserInterface で実装しなければなりません
今回はユーザー特定の為のカラムがidではないため、
それに合う様に用意します
namespace App\Authenticate;

use Illuminate\Auth\GenericUser;

/**
 * Class AdminUser
 * @package App\Authenticate
 */
class AdminUser extends GenericUser
{
    
    /**
     * @return mixed
     */
    public function getAuthIdentifier()
    {
        return $this->attributes['administrator_id'];
    }

} 
といってもこの例ではキーが異なるだけなので、extendsして、該当の部分だけオーバーライドします
"remember_token"も同じ様に、任意のものに変更できます
そしてこれらをサービスプロバイダーに記述します
namespace App\Providers;

use App\Authenticate\AdminUserProvider;
use Illuminate\Support\ServiceProvider;

/**
 * Class ApplicationServiceProvider
 * @package App\Providers
 */
class ApplicationServiceProvider extends ServiceProvider
{

    public function boot()
    {
        $this->registerAuthDrivers();
    }

    public function register()
    {

    }

    protected function registerAuthDrivers()
    {
        $this->app['auth']->extend('admin', function($app) {
                return new \Illuminate\Auth\Guard(
                    new AdminUserProvider, $app['session.store']
                );
            }
        );
    }
} 
Authクラスは、registerの段階では読み込まれていないため、bootに記述します
このあたりの流れはLaravel日本語レシピにあったハズ・・・
appはコンテナ(Laravel5ではサービスコンテナという名称に)で、
Authのクラスは、"auth"で登録されています
extendでドライバーを追加していきます
詳しくは、Facade Class Reference を参照して下さい
これで利用準備が整いました
ドライバーの追加はものすごく簡単というのはお分かりいただけましたか?
あとは用途によってドライバーを変更できれば良いわけです

利用方法は

通常のユーザはこれまで通り以下の様に認証します
\Auth::attempt(['username' => 'hoge', 'password' => 'hoge']);
\Auth::getUser();
今まで通りユーザーが返却されるはずです
では管理者を操作してみましょう
パスワードはmd5を利用して生成された値です
md5("hoge");
Authは、データベースのconnectionと同じ様に、利用するドライバーを指定する事が出来ます
adminというドライバーを用意しましたのでそれを指定します
\Auth::driver('admin')->getUser();
まずはログインさせる前に先ほどのユーザーが取得されない事を確認してください
同様にログインは、
\Auth::driver('admin')->attempt(['username' => 'hoge', 'password' => 'hoge']);
となります。
簡単ですね
これらを使ってみなさんの実装のヒントになれば幸いです

こちらもどうぞ
Laravel Recipes日本語版 | Authファサードのレシピ

レシピ書きたい方はお気軽にどうぞ!

about ytake

執筆に参加しています


Laravel お役立ち情報

share



このエントリーをはてなブックマークに追加

Categories

laravel 45

DTM 0

music 0

PHP全般 31

0

JAPAN 1

WORLD 1

javascript 4

RDBMS 1

NoSQL 1

NewSQL 1

Recent Posts

Ad

comments powered by Disqus

GitHub

Social Links

Author


クリエイティブ・コモンズ・ライセンス
Yuuki Takezawa 作『Ytake Blog』はクリエイティブ・コモンズ 表示 - 非営利 4.0 国際 ライセンス で提供されています。

© ytake/comnect All Rights Reserved. 2014