laravel5.1でlaravel マルチ認証(一般ユーザと管理者ユーザで挙動を変更する)の実装について(5.2では実装済)
手順リスト
1, 管理者ユーザテーブルを生成
2, administratorsテーブル定義
3, administratorモデルを生成する(App/Administrator.phpが生成)
4, 管理者ユーザをSeederで生成しておく(INSERTデータ)
5, 認証IDを変更するためのApp/AdminUser.phpを追加する。
6, カスタム認証ドライバ(プロバイダ)を生成(admin用)
7, laravelにサービスプロバイダを登録する
8, 実際にログイン・ログアウトしてみる。
9, カスタム認証ドライバ(プロバイダ)をミドルウェア化する
10, routes.phpでgroupとして/admin以下は、管理者しかアクセスできないようにする。
面倒臭いな~。LTS5.1の段階でマルチ認証しておいて欲しかったわ~。
参考URL
http://qiita.com/zaburo/items/5536bff2435b55c758f9
1, 管理者ユーザテーブルを生成
php artisan make:migration create_administrators_table –table=administrators
2, administratorsテーブル定義
usersテーブルには無いadministrators_idカラムがあるが、これは識別IDがusersと重なると
usersテーブルでid=1のレコードが認証後は
administratorsテーブルでid=1のレコードは認証済である!!とlaravelに認識されてしまう…。
逆も然りなので、idのプレフィックスとしてadmin_という文字列を連結して、laravelが認識できるようにする。
※1, 標準のログインIDは、emailなのでusernameに変更する。
※2, 権限用のロールも追加しておく
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
<?php use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateAdministratorsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('administrators', function(Blueprint $table) { $table->increments('id'); // usersテーブルと認証IDが重なると、両方ともログイン状態になってしまうのでプレフィックスを付与する $table->string('administrator_id',128)->unique("admin_"); $table->string('username')->unique()->comment('email代わりのログインID'); $table->string('role'); $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('administrators'); } } |
3, administratorモデルを生成する(App/Administrator.phpが生成)
php artisan make:model Administrator
User.phpのテーブル名を変更しただけ!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<?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; class Administrator extends Model implements AuthenticatableContract, CanResetPasswordContract { use Authenticatable, CanResetPassword; protected $table = 'administrators'; protected $fillable = ['name', 'email', 'password']; protected $hidden = ['password', 'remember_token']; } |
4, 管理者ユーザをSeederで生成しておく(INSERTデータ)
database/seeds/DatabaseSeeder.phpを修正
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
<?php // 管理者ユーザ use App\Administrator; // 全体のレコード生成 class DatabaseSeeder extends Seeder { public function run() { Model::unguard(); // $this->call(UserTableSeeder::class); $this->call(AdministratorsTableSeeder::class); Model::reguard(); } } // 管理者レコードを生成 class AdministratorsTableSeeder extends Seeder { public function run() { // 既存のレコード削除 Administrator::truncate(); // 管理者レコードを生成 Administrator::insert([ [ 'administrator_id'=>uniqid(), 'name'=>'管理者', 'username'=>'admin', 'role'=>'admin', 'email'=>'admin@test.com', 'password'=>Hash::make('admin') ], [ 'administrator_id'=>uniqid(), 'name'=>'管理者その2', 'username'=>'admin2', 'role'=>'general', 'email'=>'admin2@test.com', 'password'=>Hash::make('admin2') ] ]); } } |
5, 認証IDを変更するためのApp/AdminUser.phpを追加する。
1 2 3 4 5 6 7 8 9 10 |
<?php namespace App; use Illuminate\Auth\GenericUser; class AdminUser extends GenericUser { public function getAuthIdentifier(){ return $this->attributes['administrator_id']; } } |
6, カスタム認証ドライバ(プロバイダ)を生成(admin用)
php artisan make:provider AdministratorProvider
app/Providers/AdministratorProvider.phpが生成される (Illuminate/Auth/DatabaseUserProvider.phpからコピペ&修正を行う)
基本的には、認証IDをadministrator_idに変更しているだけ!
プロバイダのメソッドは、微妙に分かりづらい…。
register(laravel起動時に読み込まれる)
boot(全プロバイダが読み込まれた後に実行される。authとか使える状態になっている)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
<?php namespace App\Providers; use Illuminate\Support\ServiceProvider; use Illuminate\Auth\Guard; use DB; use Hash; use Log; use Illuminate\Contracts\Auth\UserProvider; use Illuminate\Database\ConnectionInterface; use Illuminate\Contracts\Hashing\Hasher as HasherContract; use Illuminate\Contracts\Auth\Authenticatable as UserContract; use Illuminate\Auth\GenericUser; use App\AdminUser; // 認証IDをadministrator_idに変更したUser.php class AdministratorProvider extends ServiceProvider { // register()は必須。laravel起動時に読み込まれる。 public function register() { $this->app->bind( 'Illuminate\Contracts\Auth\Registrar', 'App\Services\Registrar' ); } // boot()はオプション。 // 他の全サービスプロバイダーが登録し終えてから呼び出されます。 // つまり、他のサービスプロバイダ(この場合hは、auth機能)が使える状態になっている。 public function boot() { $this->app['auth']->extend('admin',function($app){ return new Guard(new AdminUserProvider,$app['session.store']); }); } } // 管理者の認証を実際に処理しているクラス(全部オーバーライドで書き換えているだけ) class AdminUserProvider implements UserProvider { // 認証に使うテーブルは、usersではなくadministrators protected $table = "administrators"; // ID検索 public function retrieveById($identifier) { // administrator_idで検索! //$user = DB::table($this->table)->find($identifier); $user = DB::table($this->table) ->where('administrator_id',$identifier) ->first(); return $this->getGenericUser($user); } // remember_token検索(認証済チェックボックスで、cookieに保存されている値) public function retrieveByToken($identifier, $token) { $user = DB::table($this->table) ->where('administrator_id', $identifier) ->where('remember_token', $token) ->first(); return $this->getGenericUser($user); } // remember_token更新処理 public function updateRememberToken(UserContract $user, $token) { DB::table($this->table) ->where('administrator_id', $user->getAuthIdentifier()) ->update(['remember_token' => $token]); } // ID(email)とパスワードによる認証 public function retrieveByCredentials(array $credentials) { // IDとパスワードが一致するレコードを取得する $query = DB::table($this->table); foreach ($credentials as $key => $value) { if ( ! str_contains($key, 'password')) { $query->where($key, $value); } } $user = $query->first(); return $this->getGenericUser($user); } // 認証済のユーザ情報を取得する protected function getGenericUser($user) { if ($user !== null) { //return new GenericUser((array) $user); return new AdminUser((array)$user); } } // 入力されたパスワードをハッシュ化して、DBのパスワードと一致しているか?のチェック public function validateCredentials(UserContract $user, array $credentials) { $plain = $credentials['password']; return Hash::check($plain,$user->getAuthPassword()); } } |
7, laravelにサービスプロバイダを登録する
config/app.phpに追加するだけ。
1 2 3 4 5 6 7 8 9 10 11 |
'providers' => [ /* * Laravel Framework Service Providers... */ // 既存のプロバイダが色々と登録されているので、最後に追加する。 // 管理者の独自認証プロバイダ App\Providers\AdministratorProvider::class, ], |
8, 実際にログイン・ログアウトしてみる。
app/Http/route.phpに追加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
// 管理者の認証 Route::get('admin',function(){ //認証(ログイン)変更するとログイン出来ない Auth::driver('admin')->attempt(['email'=>'admin@test.com','password'=>'admin']); //情報取得 $admin = Auth::driver('admin')->user(); // 情報を取得できたら、名前を表示する return empty($admin->name) ? 'ログインできません!' : $admin->name ; }); // 管理者のログアウト Route::get('logout',function(){ Auth::driver('admin')->logout(); }); [php] <strong>9, カスタム認証ドライバ(プロバイダ)をミドルウェア化する</strong> php artisan make:middleware AdminAuthenticate App\Http\Middleware\AdminAuthenticate.phpが生成される。 [php] <?php namespace App\Http\Middleware; use Closure; class AdminAuthenticate { public function handle($request, Closure $next) { // 認証が通っていれば、リクエスト通りの画面へ if(\Auth::driver('admin')->check()){ return $next($request); // まだ認証されていなければ、ログイン画面へ }else{ return redirect('admin/login'); } } } |
10, routes.phpでgroupとして/admin以下は、管理者しかアクセスできないようにする。
ミドルウェア化しておくと、こうやってグループ化できるので便利!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
Route::get('/admin/auto_login',function(){ //認証(ログイン) //Auth::driver('admin')->attempt(['email'=>'admin@test.com','password'=>'admin']); Auth::driver('admin')->attempt(['username'=>'admin2','password'=>'admin2']); //情報取得 $admin = Auth::driver('admin')->user(); // 情報を取得できたら、名前とロールを表示する return empty($admin->name) ? 'ログインできません!' : $admin->name .' role = '. $admin->role; }); Route::get('/admin/login',function(){ return 'ログイン画面です'; }); // 管理者のログアウト Route::get('/admin/logout',function(){ Auth::driver('admin')->logout(); }); // /admin以下は、管理者認証していないとアクセスできない! Route::group(['prefix'=>'admin','middleware'=>'admin'],function(){ Route::get('/',function(){ return "アドミンのルート"; }); Route::get('test',function(){ return "ここは、/admin/testです。"; }); }); |