マルチ認証と言っても、複数のステップでユーザーを認証するわけでもなく、ちょっとピンと来ないですね。
例えば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()
と明確にガード名を指定する必用があります。
メルマガ購読の申し込みはこちらから。