Laravelは素晴らしいフレームワークです。ほとんど文句はありません。が、唯一の不満がMulti-Authに標準で対応していなかったことです。が、とうとう対応したようなので使ってみます。
ここでいうMulti-Authとは、認証用のユーザーテーブルとしてusersとadminsと別のテーブルを利用するようなものを意味しています。
これで、今までの苦労も報われます。
##準備
では、認証に使うテーブルを作成するためのmigrateファイルや初期ユーザー登録用のseeder等を作成してみます。作成するものは、
- テーブル(migrateすることにより作成します)
- モデル(driverとしてeloquentを利用するので作成します)
- 初期ユーザー(seederで登録してみます)
###usersテーブル
####migrateファイル
usersテーブル生成用のmigrateファイルは既に、database/migrationsの中に存在していますので、それをそのまま利用します。
####モデル
usersテーブルと紐づくUserモデルは既にapp/User.phpとして存在していますので、それをそのまま利用します。
####UserTableSeeder
usersテーブルにテスト用の初期ユーザーを登録するためのseederを用意します。
php artisan make:seeder UserTableSeeder
とすると、database/seeds以下にUserTableSeeder.phpが生成されますので、それを下記のようにします。
<?php
use Illuminate\Database\Seeder;
use App\User;
class UserTableSeeder extends Seeder
{
public function run()
{
//削除
User::truncate();
//User生成
$user = new User;
$user->name = "user1";
$user->email = "user1@user.com";
$user->password = Hash::make('user1');
//保存
$user->save();
}
}
###adminsテーブル
続いてadminsテーブルの準備をしていきます。
####migrateファイル
usersとは違い、adminsテーブル用のmigrateファイルはないので生成します。雛形は、
php artisan make:migration create_admins_table --create=admins
とすることで、生成されます。後は、users用のmigrateファイルを参考にして、下記のようにします。
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateAdminsTable extends Migration
{
public function up()
{
Schema::create('admins', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email')->unique();
$table->string('password', 60);
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('admins');
}
}
####モデル
モデルを生成します。雛型は、
php artisan make:model Admin
とすることで生成可能です。
User.phpと同じにしてもいいですが、ここでは継承するクラスだけModelからAuthenticatableに変えて置きます。
<?php
namespace App;
use Illuminate\Foundation\Auth\User as Authenticatable;
class Admin extends Authenticatable
{
//
}
####AdminTableSeeder
seederを用意します。
<?php
use Illuminate\Database\Seeder;
use App\Admin;
class AdminTableSeeder extends Seeder
{
public function run()
{
//削除
Admin::truncate();
//Admin生成
$admin = new Admin;
$admin->name = "admin1";
$admin->email = "admin1@admin.com";
$admin->password = Hash::make('admin1');
//保存
$admin->save();
}
}
migrateファイルとseederの準備ができたのでテーブルを作成し、初期データを登録します。
###Migrate
php artisan migrate
###Seeder
php artisan db:seed
これで準備ができました。
##利用してみる
###auth.phpの編集
基本的には、providersとguardsをいじれば大丈夫です。
パスワードリセットを使うのならpasswordsも設定しておきます。
<?php
return [
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
//追加
'user' => [
'driver' => 'session',
'provider' => 'users',
],
//追加 for admin
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
//追加 for admin
'admins' => [
'driver' => 'eloquent',
'model' => App\Admin::class,
],
],
'passwords' => [
'users' => [
'provider' => 'users',
'email' => 'auth.emails.password',
'table' => 'password_resets',
'expire' => 60,
],
//追加 for admin
'admin' => [
'provider' => 'admins',
'email' => 'auth.emails.password',
'table' => 'password_resets',
'expire' => 60,
],
],
];
###動作確認(とりあえず)
毎度の手抜きで、とりあえずroute.phpに記述して動作確認をしてみます。
本当はMiddleware等で実装すべきです(暇な時に追記します。雑なものでよければをこっちに書いてます)。
Route::get('admin',function(){
//Guardを選択(admin)
$auth = Auth::guard('admin');
//認証
if($auth->attempt(['email'=>'admin@admin.com','password'=>'admin1']))
{
echo "You are Admin!";
}else{
echo "You are not Admin!";
}
return;
});
Route::get('user',function(){
//Guardを選択(user)
$auth = Auth::guard('user');
//認証
if($auth->attempt(['email'=>'user1@user.com','password'=>'user1']))
{
echo "You are User!";
}else{
echo "You are not User!";
}
return;
});
動きました。
Multi-Authが本家に実装されたことで、少しはぐっすり眠れるようになります(追記:ぐっすり眠れませんでした、下記動作確認2をご覧下さい)。
###動作確認2(重要)
メソッド間で認証情報が保持されず???という感じでしたが、Laravel5.2から、認証を含むSessionの保持(やCSRF,Cookie等)の処理ポリシーが変わったようで、webミドルウエアを通す必要があるようです。route.phpに新しくgroupが追加されていたので???と思っていましたが、このためのようです。
なので、下記のソースでは、/adminで取得した認証は、/hogeに共有されません。
Route::get('admin',function(){
if(Auth::guard('admin')->attempt(['email'=>'admin1@admin.com','password'=>'admin1']))
{
return redirect('hoge');
}else{
return "You are not admin.";
}
});
Route::get('hoge',function(){
return Auth::guard('admin')->user()->name;
});
認証やSession状態を共有するためには、下記の様に、webミドルウエアを適用する必要があるようです。
Route::group(['middleware' => ['web']], function () {
//
Route::get('admin',function(){
if(Auth::guard('admin')->attempt(['email'=>'admin1@admin.com','password'=>'admin1']))
{
return redirect('hoge');
}else{
return "You are not admin.";
}
});
Route::get('hoge',function(){
return Auth::guard('admin')->user()->name;
});
});
ここに書いてありました。
###動作確認3
ログインした後のページは、adminしかアクセスさせない場合、authミドルウエアにguardを指定すればOK
class AdminController extends Controller
{
public function __construct()
{
$this->middleware('auth:admin', ['except' => 'index']);
}
}
guardが指定されない場合は、auth.phpで設定された値が使用されます。
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
###メモ
5.2からroute.phpに、
/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| This route group applies the "web" middleware group to every route
| it contains. The "web" middleware group is defined in your HTTP
| kernel and includes session state, CSRF protection, and more.
|
*/
Route::group(['middleware' => ['web']], function () {
});
という記述が追加されています。HTTP系の処理は基本、webミドルウエアをかませるほうがいいようです。