Laraveで複数種類のログインを実装する方法
目次
世にあふれるログイン実装の記事ってシンプルすぎません?
大抵の記事を見ると、Laravelでデフォルトで用意されているlaravel/breezeを使ってサクッとログイン画面が出来ます!ね?簡単でしょ!といった記事ばかりです。
会員向けサービスを提供するWebアプリの場合、それで十分といえるのでしょうか?
実際には異なる種類のユーザが存在することも
会員向けサービスの公開側は、会員のログイン機能がまず必要になります。ただ、それとは別に会員を管理する画面が必要になりますよね?つまりは、会員情報を管理するための管理者ユーザも必要です。
当然管理画面用の別のログイン画面も必要になります。
複数レイヤーでのログイン実装
では複数レイヤーのログイン機能を実装するにはどうするべきでしょうか?
例えば、次のような予約システムを考えてみます。
- 複数店舗を管理する管理者
- 予約を管理する店舗
- 予約するユーザ
guardの設定
複数レイヤーでのログインではguardという機能を利用します。
各ユーザのテーブルとguardを次の用に定義します。
| ユーザの種類 | テーブル | guard |
| 管理者 | admin_users | admin |
| 店舗 | shop_users | shop |
| ユーザ | users | user |
config/auth.phpに次のようにguardを設定します。
'guards' => [
'admin' => [
'driver' => 'session',
'provider' => 'admin_users',
],
'shop' => [
'driver' => 'session',
'provider' => 'shop_users',
],
'user' => [
'driver' => 'session',
'provider' => 'users',
],
],
'providers' => [
'admin_users' => [
'driver' => 'eloquent',
'model' => App\Models\Entities\AdminUser::class,
],
'shop_users' => [
'driver' => 'eloquent',
'model' => App\Models\Entities\ShopUser::class,
],
'users' => [
'driver' => 'eloquent',
'model' => App\Models\Entities\User::class,
],
],
ログイン機能
ログイン用のControllerとFormRequestは次のように設定します。
class LoginController extends Controller
{
public function showLoginForm()
{
return view('admin.auth.login');
}
public function login(LoginRequest $request)
{
$request->authenticate();
$request->session()->regenerate();
if(redirect()->intended()->getRequest()->routeIs('admin.*')){
return redirect()->intended(route('admin.dashboard'));
}
return redirect()->route('admin.dashboard');
}
public function logout(Request $request)
{
Auth::guard('admin')->logout(); //管理者用のguardからログアウト
return redirect()->route('admin.auth.login_form');
}
}
class LoginRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'email' => 'required|string|email',
'password' => 'required|string',
];
}
/**
* Attempt to authenticate the request's credentials.
*
* @return void
*
* @throws \Illuminate\Validation\ValidationException
*/
public function authenticate()
{
$this->ensureIsNotRateLimited();
//guardを指定してログイン認証
if (! Auth::guard('admin')->attempt($this->only('email', 'password'), $this->boolean('remember'))) {
RateLimiter::hit($this->throttleKey());
throw ValidationException::withMessages([
'email' => __('auth.failed'),
]);
}
RateLimiter::clear($this->throttleKey());
}
管理画面での一例ですが、店舗、ユーザ向けはそれぞれguardの名称をそれぞれのものにして実装します。
ルーティング
ルーティング設定でもmiddlewareで各guardごとに認証の有無をチェックします。
Route::group(['namespace' => 'Admin', 'prefix' => 'admin', 'as' => 'admin.'], function () {
Route::middleware('guest:admin')->group(function() {
Route::group(['namespace' => 'Auth', 'as' => 'auth.'], function () {
Route::get('/login', 'LoginController@showLoginForm')->name('login_form');
Route::post('/login', 'LoginController@login')->name('login');
Route::get('/forgot_password', 'PasswordController@forgot')->name('forgot_password');
Route::post('/request_password', 'PasswordController@request')->name('request_password');
Route::get('/reset_form/{token}', 'PasswordController@resetForm')->name('reset_form');
Route::post('/reset/{token}', 'PasswordController@reset')->name('reset_password');
});
});
// 管理者としてログインしている場合のみアクセスを許可する
Route::middleware('auth:admin')->group(function() {
Route::get('/', function(){return view('admin.dashboard');})->name('dashboard');
Route::group(['namespace' => 'Auth', 'as' => 'auth.'], function () {
Route::get('/logout', 'LoginController@logout')->name('logout');
});
load_php_files(__DIR__ . '/web/admin'); // その他の管理画面のルーティングファイル読込
});
});
店舗、ユーザ向けはそれぞれguardの名称とnamespace、prefixを変更して実装します。
まとめ
通常のシンプルなログインはAuthファサードを利用してログイン、ログアウトを制御しますが、そこにguardを追加するのみでシンプルに複数レイヤーでのログインが実装できることが分かります。
ログアウト処理もguardごとに行うので、店舗とユーザとして別タブでログインしていても一方のみログアウト、もう一方はログイン状態を維持といったことも可能になります。



















