はじめに

例えば何かしらのWebサービスで、サービス利用者としてのユーザーとサービス運営者としての管理者のアカウントをそれぞれ別のテーブルで管理して別々で認証させたい、という時の作業内容についてのメモ。

ユーザー認証

Laravelに用意されているスカフォールドを使う。

$ php artisan make:auth
$ php artisan migrate

users テーブルと必要なコントローラー、ビューのファイルが作成される。以下のルーティングが追加される。

$ php artisan route:list
+--------+-----------+------------------------------+----------------------+------------------------------------------------------------------------+--------------+
| Domain | Method    | URI                          | Name                 | Action                                                                 | Middleware   |
+--------+-----------+------------------------------+----------------------+------------------------------------------------------------------------+--------------+
|        | GET|HEAD  | home                         |                      | App\Http\Controllers\HomeController@index                              | web,auth     |
|        | POST      | login                        |                      | App\Http\Controllers\Auth\LoginController@login                        | web,guest    |
|        | GET|HEAD  | login                        | login                | App\Http\Controllers\Auth\LoginController@showLoginForm                | web,guest    |
|        | POST      | logout                       | logout               | App\Http\Controllers\Auth\LoginController@logout                       | web          |
|        | POST      | password/email               |                      | App\Http\Controllers\Auth\ForgotPasswordController@sendResetLinkEmail  | web,guest    |
|        | POST      | password/reset               |                      | App\Http\Controllers\Auth\ResetPasswordController@reset                | web,guest    |
|        | GET|HEAD  | password/reset               |                      | App\Http\Controllers\Auth\ForgotPasswordController@showLinkRequestForm | web,guest    |
|        | GET|HEAD  | password/reset/{token}       |                      | App\Http\Controllers\Auth\ResetPasswordController@showResetForm        | web,guest    |
|        | POST      | register                     |                      | App\Http\Controllers\Auth\RegisterController@register                  | web,guest    |
|        | GET|HEAD  | register                     | register             | App\Http\Controllers\Auth\RegisterController@showRegistrationForm      | web,guest    |
+--------+-----------+------------------------------+----------------------+------------------------------------------------------------------------+--------------+

管理者認証

テーブル

マイグレーションで管理者用のテーブルを作成する。

$ php artisan make:migration create_admin_users_table

今回はusers テーブルの内容を元に作成した。

<?php
// database/migrations/yyyy_mm_dd_*_create_admin_users_table.php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateAdminUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('admin_users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('email')->unique();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('admin_users');
    }
}
$ php artisan migrate

admin_users テーブルが作成される。

モデル

App/User.php をコピーしてApp/AdminUser.php を作成する。クラス名以外は特に変更点なし。

設定

config/auth.php を以下のように変更する。

<?php

return [

    'defaults' => [
        'guard' => 'user',
        'passwords' => 'users',
    ],

    'guards' => [
        'user' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'token',
            'provider' => 'users',
        ],

        'admin' => [
            'driver' => 'session',
            'provider' => 'admin_users',
        ],
    ],
    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\User::class,
        ],

        'admin_users' => [
            'driver' => 'eloquent',
            'model' => App\AdminUser::class,
        ],
    ],

    'passwords' => [
        'users' => [
            'provider' => 'users',
            'table' => 'password_resets',
            'expire' => 60,
        ],
        'admin_users' => [
            'provider' => 'admin_users',
            'table' => 'password_resets',
            'expire' => 60,
        ],
    ],

];

ルーティング

routes/web.php に以下のルーティングを追加する。

Route::group(['prefix' => 'admin'], function() {
  $this->get('login', 'Admin\Auth\LoginController@showLoginForm');
  $this->post('login', 'Admin\Auth\LoginController@login');
  $this->post('logout', 'Admin\Auth\LoginController@logout');

  Route::get('/home', 'Admin\HomeController@index');
});

コントローラー

app/Http/Controllers/Auth/LoginController.php をapp/Http/Controllers/Admin/Auth/LoginController.php にコピーして以下のように変更する。

<?php

namespace App\Http\Controllers\Admin\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Support\Facades\Auth;

class LoginController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Login Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles authenticating users for the application and
    | redirecting them to your home screen. The controller uses a trait
    | to conveniently provide its functionality to your applications.
    |
    */

    use AuthenticatesUsers;

    /**
     * Where to redirect users after login.
     *
     * @var string
     */
    protected $redirectTo = '/admin/home';

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest', ['except' => 'logout']);
    }

    /**
     * Show the application's login form.
     *
     * @return \Illuminate\Http\Response
     */
    public function showLoginForm()
    {
        return view('admin.auth.login');
    }

    /**
     * Get the guard to be used during authentication.
     *
     * @return \Illuminate\Contracts\Auth\StatefulGuard
     */
    protected function guard()
    {
        return Auth::guard('admin');
    }
}

app/Http/Controllers/HomeController.php をapp/Http/Controllers/Admin/HomeController.php にコピーして以下のように変更する。

<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class HomeController extends Controller
{
    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth:admin');
    }

    /**
     * Show the application dashboard.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        return view('admin.home');
    }
}

ビュー

resources/views/auth/login.blade.php をresources/views/admin/auth/login.blade.php にコピーして以下の箇所を変更する。

<form class="form-horizontal" role="form" method="POST" action="{{ url('/admin/login') }}">

resources/views/home.blade.php をresources/views/admin/home.blade.php にコピーする。

その他

app/Exceptions/Handler.php のunauthenticated() を以下のように変更する。

protected function unauthenticated($request, AuthenticationException $exception)
{
    if ($request->expectsJson()) {
        return response()->json(['error' => 'Unauthenticated.'], 401);
    }

    if (in_array('admin', $exception->guards())) {
        return redirect()->guest('admin/login');
    }

    return redirect()->guest('login');
}

確認

ユーザーはブラウザから/register にアクセスして登録する。管理者の登録画面は今回用意していないので別途作成する。

ユーザーは/login からログインすると/home に遷移する。未ログイン状態で/home にアクセスすると/login にリダイレクトする。

管理者は/admin/login からログインすると/admin/home に遷移する。未ログイン状態で/admin/home にアクセスすると/admin/login にリダイレクトする。

ユーザーは管理者のログイン画面からはログインできず、管理者もユーザーのログイン画面からはログインできない。