###追記
Laravel5.2に正式にMulti−Authに対応しました。なので、この記事はもう役割終了です。
こちらをどうぞ。
私にとってLaravelの最大の難所は、Multi Authです。つまり、標準ではusersテーブルのみで行われる認証を、users(一般ユーザー)、admins(管理者)に分けた認証です。
極力自力作成派なので、
- テーブルを分けないパターン(usersにroleを追加)
- テーブルを分けるパターン
を過去にトライしてみたのですが、毎日の実装の中で気楽に利用できるレベルではないと感じました。そこで、頼りたいのが、サードパーティー製のパッケージ?なのですが、なかなかこれというものがありません。
##Multi Authパッケージの現状(2015年7月27日時点)
私の知る限り、4.2までは、ollieread/multiauthというのが主流だったようなのですが、5.xに対応しておらず、いくつかのフォークが存在するも、password_resetは動かないとか、いろいろと制限があるようです。
そのような中、5.1対応をうたう真新しいパッケージを発見!
パスワードリセットへの対応もしているようです。
Authを中心に動かしてみたのでやりかたをメモしておきます。
##Kbwebs/MultiAuthを試す:準備
流れとしては次のような感じ
- Kbwebs/MultiAuthを設置
- 一般ユーザー用のテーブルとしてはusersテーブル(既存migrationファイル)を使う。
- モデルとしてはUserを使う。
- 管理者用テーブルとしてadminsテーブルを作る。但し、内容はusersと同じ。
- モデルとしてはAdminを使う(新規作成)。
- Seederでusers, adminsにユーザーを追加
- 各種認証を試す。
###Kbwebs/MultiAuthを設置する
基本は、本家のサイトのインストール手順通りに行う。
####ファイルの取得
composer.jsonを編集。
"require": {
"kbwebs/multiauth": "dev-master"
}
update。
composer update
####使えるようにする(Auth機能)
config/app.phpのAuthServiceProviderの差し替える。
Illuminate\Auth\AuthServiceProvider::class
↓
Kbwebs\MultiAuth\AuthServiceProvider::class
####使えるようにする(PasswordReset機能:使う場合)
Illuminate\Auth\Passwords\PasswordResetServiceProvider::class
↓
Kbwebs\MultiAuth\PasswordResets\PasswordResetServiceProvider::class
config/auth.phpの書き換え
'multi-auth' => [
'admin' => [
'driver' => 'eloquent',
'model' => App\Admin::class
],
'user' => [
'driver' => 'eloquent',
'model' => App\User::class
]
]
注意点としては、App\Admin::classを''で囲わないこと。
eloquentではなく、databaseを利用する場合は、
'multi-auth' => [
'admin' => [
'driver' => 'database',
'table' => 'admins'
],
'user' => [
'driver' => 'database',
'table' => 'users'
]
],
とする。
また、パスワードリセットを使う場合は、
'password' => [
'email' => 'emails.users.password',
'table' => 'password_resets',
'expire' => 60,
],
とする必要があるようだ(emailにusersを追加)。
###usersテーブルを作る
既にあるmigrateファイルをそのまま利用し、migrateする。
###Userモデルを作る
既にあるApp\Userを使う。
###adminsテーブルを作る
php artisan make:migration create_admins_table --create=admins
として、migrateのひな形を作り、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();
});
}
public function down()
{
Schema::drop('admins');
}
}
###Adminモデルを作る
モデルは、Userをリネームして、Admin.phpを生成し必要な箇所を変更するか、artisanコマンドでひな形を生成し、Userを参考に編集します。
php artisan make:model Admin
実際の内容は、下記の通りですが、PasswordReset系のuseをKbwebsのものに変更しています。
逆にUserの方も、PasswordResetは(必要なら)変更します。
<?php
namespace App;
use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
//use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
//use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Kbwebs\MultiAuth\PasswordResets\CanResetPassword;
use Kbwebs\MultiAuth\PasswordResets\Contracts\CanResetPassword as CanResetPasswordContract;
class Admin extends Model implements AuthenticatableContract, CanResetPasswordContract
{
use Authenticatable,CanResetPassword;
protected $table = 'admins';
protected $fillable = ['name', 'email', 'password'];
protected $hidden = ['password', 'remember_token'];
}
元々のパスワードリセット系はコメントアウトし、Kbwebsのものを追加。
クラス名と、テーブル名はもちろん適切に変更する。
なお、上記コードは余計な?コメントを消去しています。
###Seederでユーザーを登録
テスト用にユーザーを登録します。ここではSeederを使ってみます。
Laravel5.1から、Seederのひな形も作れるようになりました。
php artisan make:seeder UserTableSeeder
php artisan make:seeder AdminTableSeeder
UserTableSeederはこんな感じ。
<?php
use Illuminate\Database\Seeder;
use App\User;
class UserTableSeeder extends Seeder
{
public function run()
{
//delete
User::truncate();
//Insert
User::insert([
[
'name' => 'user1',
'email' => 'user1@test.com',
'password' => Hash::make('user1')
]
]);
}
}
AdminTableSeederはこんな感じ。
<?php
use Illuminate\Database\Seeder;
use App\Admin;
class AdminTableSeeder extends Seeder
{
public function run()
{
//delete
Admin::truncate();
//Insert
Admin::insert([
'name' => 'admin1',
'email' => 'admin1@test.com',
'password' => Hash::make('admin1')
]);
}
}
artisan db:seedコマンドでの実行対象となるよう、DatabaseSeeder.phpを編集します。
<?php
use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;
class DatabaseSeeder extends Seeder
{
public function run()
{
Model::unguard();
$this->call(UserTableSeeder::class);
$this->call(AdminTableSeeder::class);
Model::reguard();
}
}
で、実行します。
php artisan db:seed
データが生成されます。※現状の記述ではModelに問題があり、エラーが発生します(調査中)。
##Kbwebs/MultiAuthを試す:利用
利用は、
Auth::admin()->attempt(['email'=>'admin1@test.com','password'=>'admin1']);
Auth::user()->attempt(['email'=>'user1@test.com','password'=>'user1']);
という感じになります。
実際には、Middleware等を設定して利用することになるでしょう。
###Middlewareの設定例
ここでは、admin認証用とuser認証用のMiddlewareを作ってみたいと思います。まずは、ひな形。
php artisan make:middleware AdminAuthenticate
php artisan make:middleware UserAuthenticate
AdminAuthenticateは、
<?php
namespace App\Http\Middleware;
use Closure;
class AdminAuthenticate
{
public function handle($request, Closure $next)
{
if(\Auth::admin()->check())
{
//do nothing
}
else
{
return "go to admin login page.";
}
return $next($request);
}
}
とりあえずこんな感じ。adminとしてログインしてればスルー。して無ければ、loginメッセージを出します(実際にはログインページへのリダイレクトとかになると思います)。
UserAuthenticateは、
<?php
namespace App\Http\Middleware;
use Closure;
class UserAuthenticate
{
public function handle($request, Closure $next)
{
if(\Auth::user()->check())
{
//do nothing
}
else
{
return "go to user login page.";
}
return $next($request);
}
}
基本、admin認証と同じ理屈。
Middlewareをルートで利用するためには、Kernel.phpに登録します(以下、抜粋)。
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'admin' => \App\Http\Middleware\AdminAuthenticate::class,
'user' => \App\Http\Middleware\UserAuthenticate::class,
];
###利用してみる
ここでは、route.phpだけの記述でlogin,認証,logout等が正しく動くがチェックしてみます。
//admin
Route::get('admin/login',function(){
Auth::admin()->attempt(['email'=>'admin1@test.com','password'=>'admin1']);
return Auth::admin()->get()->email;
});
Route::get('admin/logout',function(){
Auth::admin()->logout();
return "admin logout";
});
Route::get('admin',['middleware'=>'admin',function(){
return "admin page";
}]);
//user
Route::get('user/login',function(){
Auth::user()->attempt(['email'=>'user1@test.com','password'=>'user1']);
return Auth::user()->get()->email;
});
Route::get('user/logout',function(){
Auth::user()->logout();
return "user logout";
});
Route::get('user',['middleware'=>'user',function(){
return "user page";
}]);
なお、prefixを使って、下記の様に書くこともできる。
Route::group(['prefix'=>'admin','middleware'=>'admin'],function(){
Route::get('/',function(){
return "admin page";
});
Route::get('login',function(){
Auth::admin()->attempt(['email'=>'admin1@test.com','password'=>'admin1']);
return Auth::admin()->get()->email;
});
});
上記をroute.phpに設定したら、下記テストを行います。
-
adminページにアクセスしてみる。login促しメッセーがでれば、正しく「拒否されている」。
-
admin/loginにアクセスし、ログイン。ユーザー名が正しく取得できていればログイン完了。
-
再びadminにアクセスし、"admin page"が表示されていれば、認証されている。
-
admin/logoutにアクセスし、ログアウトする。
-
再びadminにアクセスし、login促しメッセージが表示されればOK。
-
userにおいても、上記と同じテストを行う。
-
userにログイン状態で、adminにアクセスするとどうなるか試してみる。
-
adminにログイン状態でuserにアクセスするとどうなるか試してみる。
####注意
adminとuserのログインは同時に行うことが可能なので、テストの際は、気をつける。
####パスワードリセット
私は、標準のパスワードリセットをあまり使わないので、いろいろ端折りましたが、本家サイトにパスワードリセットを使う場合の注意書きがまとまっています。
主な留意点としては、
- Modelにkbwebsの機能をuseする。
- config/auth.phpで'email' => 'emails.users.password'とする。
- パスワードリセット用テーブルは独自のものを生成する。
専用のリセットテーブルは、下記のコマンドで、
php artisan kbwebs:multi-auth:create-resets-table
php artisan kbwebs:multi-auth:clear-resets
マイグレーションファイルの生成、全パスワードリセットができるみたいです。なお、Kbwebs独自のartisanコマンドを利用するには、ProviderにKbwebs\MultiAuth\PasswordResets\PasswordResetServiceProvider::classの追加が必要です。