admin と professor を追加してマルチ認証を実装しよう.
設定ファイルを編集して,admin と professor の項目を追加する.このとき,単数形と複数形の使い方に注意すること.
config/auth.php
<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Defaults
|--------------------------------------------------------------------------
|
| This option controls the default authentication "guard" and password
| reset options for your application. You may change these defaults
| as required, but they're a perfect start for most applications.
|
*/
'defaults' => [
'guard' => 'user',
'passwords' => 'users',
],
/*
|--------------------------------------------------------------------------
| Authentication Guards
|--------------------------------------------------------------------------
|
| Next, you may define every authentication guard for your application.
| Of course, a great default configuration has been defined for you
| here which uses session storage and the Eloquent user provider.
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| Supported: "session", "token"
|
*/
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
'user' => [
'driver' => 'session',
'provider' => 'users',
],
'professor' => [
'driver' => 'session',
'provider' => 'professors',
],
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
],
/*
|--------------------------------------------------------------------------
| User Providers
|--------------------------------------------------------------------------
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| If you have multiple user tables or models you may configure multiple
| sources which represent each model / table. These sources may then
| be assigned to any extra authentication guards you have defined.
|
| Supported: "database", "eloquent"
|
*/
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'professors' => [
'driver' => 'eloquent',
'model' => App\Professor::class,
],
'admins' => [
'driver' => 'eloquent',
'model' => App\Admin::class,
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
/*
|--------------------------------------------------------------------------
| Resetting Passwords
|--------------------------------------------------------------------------
|
| You may specify multiple password reset configurations if you have more
| than one user table or model in the application and you want to have
| separate password reset settings based on the specific user types.
|
| The expire time is the number of minutes that the reset token should be
| considered valid. This security feature keeps tokens short-lived so
| they have less time to be guessed. You may change this as needed.
|
*/
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
],
'professors' => [
'provider' => 'professors',
'table' => 'password_resets',
'expire' => 60,
],
'admins' => [
'provider' => 'admins',
'table' => 'password_resets',
'expire' => 60,
],
],
];
admin と professor のログイン画面へのリダイレクト先を変更する.(Laravel 5.7 では app/Http/Middleware/Authenticate.php に記述するようになりました.詳細は後日公開します.)
app/Exceptions/Handler.php
<?php
namespace App\Exceptions;
use Exception;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
class Handler extends ExceptionHandler
{
/**
* A list of the exception types that should not be reported.
*
* @var array
*/
protected $dontReport = [
\Illuminate\Auth\AuthenticationException::class,
\Illuminate\Auth\Access\AuthorizationException::class,
\Symfony\Component\HttpKernel\Exception\HttpException::class,
\Illuminate\Database\Eloquent\ModelNotFoundException::class,
\Illuminate\Session\TokenMismatchException::class,
\Illuminate\Validation\ValidationException::class,
];
/**
* Report or log an exception.
*
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
*
* @param \Exception $exception
* @return void
*/
public function report(Exception $exception)
{
parent::report($exception);
}
/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $exception
* @return \Illuminate\Http\Response
*/
public function render($request, Exception $exception)
{
return parent::render($request, $exception);
}
/**
* Convert an authentication exception into an unauthenticated response.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Auth\AuthenticationException $exception
* @return \Illuminate\Http\Response
*/
protected function unauthenticated($request, AuthenticationException $exception)
{
if ($request->expectsJson()) {
return response()->json(['error' => 'Unauthenticated.'], 401);
}
if (in_array('admin', $exception->guards(), true)) {
return redirect()->guest(route('admin.login'));
}
if (in_array('professor', $exception->guards(), true)) {
return redirect()->guest(route('professor.login'));
}
return redirect()->guest(route('login'));
}
}
artisan コマンドで Admin と Professor モデルを生成する.
[GakuinHana@rin06 laravelUser]$ php artisan make:model Admin ⏎ Model created successfully. [GakuinHana@rin06 laravelUser]$ php artisan make:model Professor ⏎ Model created successfully. [GakuinHana@rin06 laravelUser]$
マイグレーションファイルを生成する.
[GakuinHana@rin06 laravelUser]$ php artisan make:migration create_admins_table --create=admins ⏎ Created Migration: 2018_07_07_152520_create_admins_table [GakuinHana@rin06 laravelUser]$ php artisan make:migration create_professors_table --create=professors ⏎ Created Migration: 2018_07_07_152539_create_professors_table [GakuinHana@rin06 laravelUser]$
生成されたマイグレーションファイルを編集する.
database/migrations/20xx_xx_x_xxxxxx_create_admins_table.php
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateAdminsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('admins', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email')->unique();
$table->string('login_id')->unique();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('admins');
}
}
database/migrations/20xx_xx_xx_xxxxxx_create_professors_table.php
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateProfessorsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('professors', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email')->unique();
$table->string('login_id')->unique();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('professors');
}
}
マイグレーションを実行する.
[GakuinHana@rin06 laravelUser]$ php artisan migrate:status ⏎ +------+------------------------------------------------+ | Ran? | Migration | +------+------------------------------------------------+ | Y | 2014_10_12_000000_create_users_table | | Y | 2014_10_12_100000_create_password_resets_table | | Y | 2018_07_01_163318_create_jobs_table | | Y | 2018_07_01_163336_create_failed_jobs_table | | N | 2018_07_07_152520_create_admins_table | | N | 2018_07_07_152539_create_professors_table | +------+------------------------------------------------+ [GakuinHana@rin06 laravelUser]$ php artisan migrate ⏎ Migrating: 2018_07_07_152520_create_admins_table Migrated: 2018_07_07_152520_create_admins_table Migrating: 2018_07_07_152539_create_professors_table Migrated: 2018_07_07_152539_create_professors_table [GakuinHana@rin06 laravelUser]$ php artisan migrate:status ⏎ +------+------------------------------------------------+ | Ran? | Migration | +------+------------------------------------------------+ | Y | 2014_10_12_000000_create_users_table | | Y | 2014_10_12_100000_create_password_resets_table | | Y | 2018_07_01_163318_create_jobs_table | | Y | 2018_07_01_163336_create_failed_jobs_table | | Y | 2018_07_07_152520_create_admins_table | | Y | 2018_07_07_152539_create_professors_table | +------+------------------------------------------------+ [GakuinHana@rin06 laravelUser]$
テスト用のシーダーを生成する.
[GakuinHana@rin06 laravelUser]$ php artisan make:seeder AdminsTableSeeder ⏎ Seeder created successfully. [GakuinHana@rin06 laravelUser]$ php artisan make:seeder ProfessorsTableSeeder ⏎ Seeder created successfully. [GakuinHana@rin06 laravelUser]$
シーダーにテストデータを追加する.
database/seeds/DatabaseSeeder.php
<?php
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$this->call(UsersTableSeeder::class);
$this->call(AdminsTableSeeder::class);
$this->call(ProfessorsTableSeeder::class);
}
}
database/seeds/AdminsTableSeeder.php
<?php
use Illuminate\Database\Seeder;
use App\Admin;
use Carbon\Carbon;
class AdminsTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
DB::table('admins')->delete();
Admin::create([
'name' => 'Taro Admin',
'email' => 'taro@sample.com',
'login_id' => 'taro',
'password' => bcrypt('admin'),
'created_at' => Carbon::now()
]);
Admin::create([
'name' => 'Jiro Admin',
'email' => 'jiro@sample.com',
'login_id' => 'jiro',
'password' => bcrypt('admin'),
'created_at' => Carbon::now()
]);
}
}
database/seeds/ProfessorsTableSeeder.php
<?php
use Illuminate\Database\Seeder;
use App\Professor;
use Carbon\Carbon;
class ProfessorsTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
DB::table('professors')->delete();
Professor::create([
'name' => 'Tama',
'email' => 'tama@sample.com',
'login_id' => 'tama',
'password' => bcrypt('professor'),
'created_at' => Carbon::now()
]);
Professor::create([
'name' => 'Pochi',
'email' => 'poch@sample.com',
'login_id' => 'pochi',
'password' => bcrypt('professor'),
'created_at' => Carbon::now()
]);
}
}
シーダーを実行する.まずは dump-autoload を実行しなければエラーになるはず.
[GakuinHana@rin06 laravelUser]$ php ../composer.phar dump-autoload ⏎ Generating optimized autoload files [GakuinHana@rin06 laravelUser]$ php artisan db:seed ⏎ Seeding: UsersTableSeeder Seeding: AdminsTableSeeder Seeding: ProfessorsTableSeeder [GakuinHana@rin06 laravelUser]$
app/Http/Controllers/ 以下に Admin と Professor というフォルダを作成する.その後,artisan コマンドでコントローラを生成する.
[GakuinHana@rin06 laravelUser]$ mkdir app/Http/Controllers/Admin ⏎ [GakuinHana@rin06 laravelUser]$ mkdir app/Http/Controllers/Professor ⏎ [GakuinHana@rin06 laravelUser]$ php artisan make:controller Admin/LoginController ⏎ Controller created successfully. [GakuinHana@rin06 laravelUser]$ php artisan make:controller Admin/HomeController ⏎ Controller created successfully. [GakuinHana@rin06 laravelUser]$ php artisan make:controller Professor/LoginController ⏎ Controller created successfully. [GakuinHana@rin06 laravelUser]$ php artisan make:controller Professor/HomeController ⏎ Controller created successfully. [GakuinHana@rin06 laravelUser]$
それぞれの認証クラスでのルートを定義する.なお,'prefix' => 'admin'
は URL の先頭に admin がつく,すなわち,「login」の URL は「/admin/login」となることを意味している.また,Route::group
の中で middleware を定義しているので,コントローラで明示的に middleware を呼び出さなくてもコントローラですべての処理に認証が要求される(ただし,このあとの例では念の為,コントローラでも middleware を呼び出している).
routes/web.php
<?php
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
return view('welcome');
});
Route::get('/auth/verifyemail/{token}', 'Auth\RegisterController@verify');
Auth::routes();
Route::get('/resend', 'Auth\RegisterController@showReSendForm')->name('resend');
Route::post('/resend', 'Auth\RegisterController@reSend');
Route::get('/password/change', 'Auth\ChangePasswordController@edit');
Route::patch('/password/change','Auth\ChangePasswordController@update')->name('password.change');
// User ログイン後
Route::group(['middleware' => 'auth:user'], function() {
Route::get('/home', 'HomeController@index')->name('home');
Route::get('/users/{id}', 'UsersController@show');
});
// Admin 認証不要
Route::group(['prefix' => 'admin'], function() {
Route::get('login', 'Admin\LoginController@showLoginForm')->name('admin.login');
Route::post('login', 'Admin\LoginController@login');
});
// Admin ログイン後
Route::group(['prefix' => 'admin', 'middleware' => 'auth:admin'], function() {
Route::get('home', 'Admin\HomeController@index')->name('admin.home');
Route::post('logout', 'Admin\LoginController@logout')->name('admin.logout');
});
// Professor 認証不要
Route::group(['prefix' => 'professor'], function() {
Route::get('login', 'Professor\LoginController@showLoginForm')->name('professor.login');
Route::post('login', 'Professor\LoginController@login');
});
// Professor ログイン後
Route::group(['prefix' => 'professor', 'middleware' => 'auth:professor'], function() {
Route::get('home', 'Professor\HomeController@index')->name('professor.home');
Route::post('logout', 'Professor\LoginController@logout')->name('professor.logout');
});
artisan コマンドでルートの定義を確認しておこう.
[GakuinHana@rin06 laravelUser]$ php artisan route:list ⏎ +--------+----------+--------------------------+------------------+------------------------------------------------------------------------+--------------------+ | Domain | Method | URI | Name | Action | Middleware | +--------+----------+--------------------------+------------------+------------------------------------------------------------------------+--------------------+ | | GET|HEAD | / | | Closure | web | | | GET|HEAD | admin/home | admin.home | App\Http\Controllers\Admin\HomeController@index | web,auth:admin | | | POST | admin/login | | App\Http\Controllers\Admin\LoginController@login | web | | | GET|HEAD | admin/login | admin.login | App\Http\Controllers\Admin\LoginController@showLoginForm | web | | | POST | admin/logout | admin.logout | App\Http\Controllers\Admin\LoginController@logout | web,auth:admin | | | GET|HEAD | api/user | | Closure | api,auth:api | | | GET|HEAD | auth/verifyemail/{token} | | App\Http\Controllers\Auth\RegisterController@verify | web,guest | | | GET|HEAD | home | home | App\Http\Controllers\HomeController@index | web,auth:user,auth | | | GET|HEAD | login | login | App\Http\Controllers\Auth\LoginController@showLoginForm | web,guest | | | POST | login | | App\Http\Controllers\Auth\LoginController@login | web,guest | | | POST | logout | logout | App\Http\Controllers\Auth\LoginController@logout | web | | | GET|HEAD | password/change | | App\Http\Controllers\Auth\ChangePasswordController@edit | web,auth | | | PATCH | password/change | password.change | App\Http\Controllers\Auth\ChangePasswordController@update | web,auth | | | POST | password/email | 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 | password.request | App\Http\Controllers\Auth\ForgotPasswordController@showLinkRequestForm | web,guest | | | GET|HEAD | password/reset/{token} | password.reset | App\Http\Controllers\Auth\ResetPasswordController@showResetForm | web,guest | | | GET|HEAD | professor/home | professor.home | App\Http\Controllers\Professor\HomeController@index | web,auth:professor | | | GET|HEAD | professor/login | professor.login | App\Http\Controllers\Professor\LoginController@showLoginForm | web | | | POST | professor/login | | App\Http\Controllers\Professor\LoginController@login | web | | | POST | professor/logout | professor.logout | App\Http\Controllers\Professor\LoginController@logout | web,auth:professor | | | GET|HEAD | register | register | App\Http\Controllers\Auth\RegisterController@showRegistrationForm | web,guest | | | POST | register | | App\Http\Controllers\Auth\RegisterController@register | web,guest | | | GET|HEAD | resend | resend | App\Http\Controllers\Auth\RegisterController@showReSendForm | web,guest | | | POST | resend | | App\Http\Controllers\Auth\RegisterController@reSend | web,guest | | | GET|HEAD | users/{id} | | App\Http\Controllers\UsersController@show | web,auth:user,auth | +--------+----------+--------------------------+------------------+------------------------------------------------------------------------+--------------------+ [GakuinHana@rin06 laravelUser]$
生成されたモデルを編集する.(同じフォルダにある User.php をコピーして一部修正しても良い.)
app/Admin.php
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class Admin extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password', 'remember_token',
];
}
app/Professor.php
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class Professor extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password', 'remember_token',
];
}
ルートに定義した関数をコントローラに設置する.とりあえず雛形だけ.
app/Http/Controllers/Admin/LoginController.php
<?php
namespace App\Http\Controllers\Admin;
use Illuminate\Foundation\Auth\AuthenticatesUsers; // 追加 (app/Http/Controllers/Auth/LoginController.php からコピーすれば良い)
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
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:admin')->except('logout');
}
public function showLoginForm()
{
dd("admin.showLoginForm");
}
protected function guard()
{
return Auth::guard('admin');
}
public function logout(Request $request)
{
$this->guard('admin')->logout();
$request->session()->invalidate();
return redirect('/admin/login');
}
public function username()
{
return 'login_id';
}
}
app/Http/Controllers/Admin/HomeController.php
<?php
namespace App\Http\Controllers\Admin;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
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()
{
dd("admin.index");
}
}
app/Http/Controllers/Professor/LoginController.php
<?php
namespace App\Http\Controllers\Professor;
use Illuminate\Foundation\Auth\AuthenticatesUsers; // 追加 (app/Http/Controllers/Auth/LoginController.php からコピーすれば良い)
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
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 = '/professor/home';
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest:professor')->except('logout');
}
public function showLoginForm()
{
dd("professor.showLoginForm");
}
protected function guard()
{
return Auth::guard('professor');
}
public function logout(Request $request)
{
Auth::gurad('professor')->logout();
$request->session()->flush();
$request->session()->regenerate();
return redirect('/professor/login');
}
public function username()
{
return 'login_id';
}
}
app/Http/Controllers/Professor/HomeController.php
<?php
namespace App\Http\Controllers\Professor;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class HomeController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth:professor');
}
/**
* Show the application dashboard.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
dd("professor.index");
}
}
ここで一旦動作を確認してみよう.Webサーバを再起動し,ログアウトした状態で /admin/home や /professor/home にアクセスすると,それぞれ /admin/login や /professor/login に転送されることが確認できるはずである.また,一般ユーザ (user) でログインしている状態でも /admin/home や /professor/home にアクセスするとやはりログイン画面に転送される.