マルチ認証と言っても、複数のステップでユーザーを認証するわけでもなく、ちょっとピンと来ないですね。
例えばECシステムにおいて、ユーザー画面での会員ログインと、管理画面での管理者のログインがそれぞれ別に必要とします。どちらもログインはEメールとは限らないし、片方でログインしたらもう片方でも認証となるとも限りません。つまり、ログインするユーザーの種類や場所が複数必要となる状況が多々あります。それに対応する機能が、マルチ認証です。
Laravelの5.1までは、マルチ認証は対応していなく、以下のようなパッケージをインストールして使用していました。
Laravel4.2対応のLaravel Multi Auth
Laravel5.1対応のMultiAuth for Laravel 5.1
しかし、5.2からはLaravelの基本仕様となっています。さすが、Taylorくん!
今回はこの機能を見てみましょう。
まず、デフォルトでインストールされるconfig/auth.phpの中身の解析。
Laravel 5.1では、
return [
    /* デフォルトの認証ドライバー */
    'driver' => 'eloquent',
    /* 認証に使用されるモデル */
    'model' => App\User::class,
    /* 認証に使用されるDBテーブル。ここでは、dirverがdatabaseでないので関係ない */
    'table' => 'users',
    /* パスワードリセットの設定 */
    'password' => [
        'email'  => 'emails.password', // resources/views/emails/passwordをリンク送信メールのテンプレートとする
        'table'  => 'password_resets',  // パスワードリセットのトークンの情報を保存するDBテーブル
        'expire' => 60,                 // トークンは60分で期限切れ
    ],
];
これがLaravel5.2では、
return [
    /* 認証のデフォルト設定 */
    'defaults' => [
        'guard' => 'web',
        'passwords' => 'users',
    ],                         
    /* 認証のガードを定義 */                                                   
    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
        'api' => [
            'driver' => 'token',
            'provider' => 'users',
        ],
    ],
    /* 認証のプロバイダー */
    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\User::class,
        ],
        // 'users' => [
        //     'driver' => 'database',
        //     'table' => 'users',
        // ],
    ],
   /* パスワードリセットの設定 */
    'passwords' => [
        'users' => [
            'provider' => 'users',
            'email' => 'auth.emails.password',
            'table' => 'password_resets',
            'expire' => 60,
        ],
    ],
];
となりました。違いは、guardsとprovidersの導入です。
ちょっとこれではわかりにくいので、先の例を使って、ECサイトを想像してもらって、ショッピングをするユーザ画面と、サイトを管理する管理者画面があり、どちらもログインで認証が必要と仮定しましょう。ユーザー画面では買い物かごをチェックアウトするには、会員のログインが必要とします。
となると必要な設定は以下にようになります。
return [
    /* 認証のデフォルト設定 */
    'defaults' => [
        'guard' => 'users',
        'passwords' => 'users',
    ],                         
    /* 認証のガードを定義 */                                                   
    'guards' => [
        'users' => [
            'driver' => 'session',
            'provider' => 'users_provider',
        ],
        'admin_users' => [
            'driver' => 'session',
            'provider' => 'admin_users_provider',
        ],
    ],
    /* 認証のプロバイダー */
    'providers' => [
        'users_provider' => [
            'driver' => 'eloquent',
            'model' => App\User::class,
        ],
        'admin_users_provider' => [
            'driver' => 'eloquent',
            'model' => App\AdminUser::class,
        ],
    ],
   /* パスワードリセットの設定 */
    'passwords' => [
        'users' => [
            'provider' => 'users_provider',
            'email' => 'auth.emails.password',
            'table' => 'password_resets',
            'expire' => 60,
        ],
    ],
];
ガードには、会員ログインのためのusersと、管理者ログインのためのadmin_usersの2つを定義します。どちらもセッションを使って、ログイン後の画面をプロテクトします。また、それらのプロバイダーで定義されているように、会員のUsersと管理者のAdminUsersのエロクエントモデルが認証のための情報提供元となります。
guardsとprovidersの概念を導入することにより、今までの1つだけの認証のメカニズムを複数としたわけです。
さて、次はこの設定の使用です。このファイル以外で使用するのは、ガード名だけですから簡単です。
ガードを指定する場所はプログラムの中でいくつかありますが、以下のようにapp/Http/routes.phpで使用されるのが一番明確と思います。
例えば、ユーザー画面では、
    Route::group(['middleware' => 'guest:users'], function() {
        Route::get('login', 'user\AuthController@getLogin');
        Route::post('login', 'user\AuthController@postLogin');
        Route::get('signup', 'user\SignupController@getSignup');
        Route::post('signup', 'user\SignupController@postSignup');
        Route::get('password/email', 'user\PasswordController@getEmail');
        Route::post('password/email', 'user\PasswordController@postEmail');
        Route::get('password/reset/{token}', 'user\PasswordController@getReset');
        Route::post('password/reset', 'user\PasswordController@postReset');
    });
    Route:: group(['prefix' => 'member', 'middleware' => 'auth:users'], function() {
        Route::get('index', 'user\MemberController@getIndex');
        Route::get('password', 'user\MemberController@getPassword');
        Route::post('password', 'user\MemberController@postPassword');
        Route::get('profile', 'user\MemberController@getProfile');
        Route::post('profile', 'user\MemberController@postProfile');
        Route::get('logout', 'user\AuthController@getLogout');
    });
以前、ユーザー認証(4)認証でページを保護で説明したように、
ミドルウェアとして、guestとauthが使われます。しかし、前回と違って、guest:usersのようにガード名を指定することが必要です。指定がないなら、auth.phpのデフォルトのセクションで指定したガードが自動的に使われます。
ちなみに、管理者側では、
Route::group(['prefix' => 'admin', 'middleware' => 'guest:admin_users'], function()
{
    Route::get('login', 'admin\AuthController@getLogin');
    Route::post('login', 'admin\AuthController@postLogin');
});
Route:: group(['prefix' => 'admin', 'middleware' => 'auth:admin_users'], function() {
    Route::get('logout', 'admin\AuthController@getLogout');
    Route::get('index', 'admin\HomeController@getIndex')->name('admin.home');
..
こんな感じです。
AuthControllerは、ユーザ画面と管理画面では、前回紹介した自動作成使われるもののコピーを編集する必用あります。
ユーザ画面では、
...
class AuthController extends BaseController
{
    protected $guard = 'users';
    protected $redirectTo = 'user/member/index';   // ログイン後のリダイレクト先
    protected $redirectAfterLogout = 'user/login';   // ログアウト後のリダイレクト先
    protected $username = 'email';               // ログインとなるDBの項目名
    protected $maxLoginAttempts = 5;             // ログインスロットルとなるまで最高のログイン失敗回数
    protected $lockoutTime = 60;                 // ログインスロットルとなってからの待ち秒数
    use AuthenticatesAndRegistersUsers, ThrottlesLogins;
    public function showLoginForm()
    {
        return view('user.login');  //テンプレートの場所を変える
    }
..
管理画面では、
...
class AuthController extends BaseController
{
    protected $guard = 'admin_users';
    protected $redirectTo = 'admin/index';   // ログイン後のリダイレクト先
    protected $redirectAfterLogout = 'admin/login';   // ログアウト後のリダイレクト先
    protected $username = 'login';               // ログインとなるDBの項目名
    protected $maxLoginAttempts = 5;             // ログインスロットルとなるまで最高のログイン失敗回数
    protected $lockoutTime = 60;                 // ログインスロットルとなってからの待ち秒数
    use AuthenticatesUsers, ThrottlesLogins;
    public function showLoginForm()
    {
        $form = new \stdClass();
        $form->login = Form::text('login', '',
            ['size' => 20, 'maxlength' => 20, 'class' => 'en', 'autofocus' => 'autofocus']);
        $form->password = Form::password('password',
            ['size' => 40, 'maxlength' => 20, 'class' => 'en']);
        return view('admin.login')->with(compact('form')); //テンプレートの場所を変える
    }
..
となります。認証が2つとなると、テンプレートなどいろいろな指定が必要となることに注意してください。上の例では、会員のログインは、emailですが、管理者のログインは、emailでなくてもよい文字列という仮定です。
最後に、ログイン後にログインしたユーザーの情報がほしいときは、今まで、
Auth::user()
でしたが、マルチ認証となると、
Auth::guard('users')->user()
Auth::guard('admin_users')->user()
と明確にガード名を指定する必用があります。
メルマガ購読の申し込みはこちらから。