Laravel4、ロールと許可ベースのルート制御(1)
タグ: Laravel4
Laravel 4でロールベースの認証を行いたい場合、実用的には既に存在するパッケージを利用するのが便利です。
Sentryは他のフレームワークにも統合されている、人気のある認証システムです。Laravel4用のパッケージの中でも、一番人気です。
Confideは認証、Entrustはロールベースのパーミッション制御を行うパッケージで、同じ作者によるものです。Laravelらしい書き方ができるようです。Sentryほどではありませんが、やはり人気があるパッケージです。
両方共、認証とロールベースのパーミッション制御以外に、パスワードリマインダーなどの機能も提供していますので、認証周りはだいぶ簡単に実現できます。
今回は学習のため、自前でロールベースのURIのアクセス制御を行いましょう。以下の機能に慣れ親しみ目的です。
- Eloquentの多対多関係
- ルーティングのBeforeフィルター
最初に、新しくLaravelをインストールしてください。デモのルートページが標示される程度に設定を済ませてください。
続いて、データベースの設定を行いましょう。マイグレーションを使用します。php artisan migrate:install
まで、済ませてください。
マイグレーションのやり方に不慣れな方は、以下のミニ・チュートリアルを先に行なってください。今回はマイグレーションの関係などは、詳しく説明しません。
テーブルの準備
今回、5テーブルを使用します。
主なものは、ユーザー認証にも使用するusersテーブル、役割のrolesテーブル、許可のpermissionsテーブルです。
usertsとroles、rolesとpermissionsは、それぞれ多対多で関連付けるため、中間テーブルが2つ必要になります。
今回はACL風のアクセス制御です。あるユーザーは複数の役割を持つことができます。ある役割には複数の許可を設定することができます。URIに対して、必要な許可をチェックするルーティングbeforeフィルターを指定することで、アクセスコントロールを行います。
システムを使用するときには、何でもできるスーバーユーザー権限を用意しておくと、便利です。そのため、役割に"super"を用意し、この権限を持ったユーザーは、全ページにアクセス可能にしましょう。
この程度の規模の制御であれば、データベースを使用するのは大げさです。設定ファイルに用意し、取り込むほうが、スピードでも有利でしょう。あくまで、学習目的です。
まず、マイグレーションをまとめて紹介します。upとdownメソッドの内容です。
usersテーブル
public function up() { Schema::create( 'users', function ($table) { $table->increments( 'id' ); $table->string( 'username', 30 ); $table->string( 'password', 64 ); $table->string( 'email', 320 ); $table->timestamps(); } ); } public function down() { Schema::dorpIfExist('users'); }
rolesテーブル
/** * Run the migrations. * * @return void */ public function up() { Schema::create( 'roles', function($table) { $table->increments( 'id' ); $table->string( 'rolename', 20 ); $table->timestamps(); } ); } public function down() { Schema::dropIfExists( 'roles' ); }
permisssionsテーブル
public function up() { Schema::create( 'permissions', function ($table) { $table->increments( 'id' ); $table->string( 'allow', 20 ); $table->timestamps(); } ); } public function down() { Schema::dropIfExists( 'permissions' ); }
主要な3つのテーブルのマイグレーションは、シンプルです。必要なフィールドを定義しているだけです。
続いて、残りの中間テーブルを作成しましょう。まずはusersとrolesの中間テーブルです。
中間テーブルの名前は、それぞれのテーブルの名前の単数形をアルファベット順に、アンダーバーでつないだものです。ですから、role_userが中間テーブルになります。もちろん、この名前はデフォルトの規約に従った場合です。規約に従わず、自由に名前を付けることも可能です。その場合、Eloquentモデル中で行う、関連付けの定義時に、明示的にそのテーブル名を指定する必要があります。
role_userテーブル
public function up() { Schema::create( 'role_user', function($table) { $table->increments( 'id' ); $table->integer( 'user_id' )->unsigned(); $table->integer( 'role_id' )->unsigned(); } ); } public function down() { Schema::dropIfExists( 'role_user' ); }
中間テーブルのフィールドは、それ自身のID、usersテーブルのIDを表すuser_id、rolesテーブルのIDを表すrole_idです。テーブルの単数名に_id
を付けたものになります。
incrementsメソッドで作成されたフィールドは符号なし整数です。ですから、user_idとrole_idはintegerメソッドで作成し、unsignedメソッドで符号なしを指定します。
同じ規約に従い、rolesテーブルと、permissionsテーブルの中間テーブルも作成しましょう。
permission_roleテーブル
public function up() { Schema::create( 'permission_role', function($table) { $table->increments('id'); $table->integer('permission_id')->unsigned(); $table->integer('role_id')->unsigned(); } ); } public function down() { Schema::dropIfExists('permission_role'); }
モデル作成
続いて、データベースに初期値を設定するため、Eloquentモデルを作成しましょう。
データベースに初期値設定するためには、外部ツールを使用することも可能ですし、使用するデータベースのコマンドラインツールを使用することもできます。今回は、Laravelのシーディングを使用して、設定します。
シーディングは、テーブルの初期値設定のことです。Eloquentを使用せずとも、クエリービルダーを使ったり、直接SQLを指定したりすることも可能ですが、やはりLaravelではEloqunetが花ですから、いろいろ使用して、慣れましょう。
関連付けも、行なっていきます。
最初にUser.phpです。User.phpは予めインストール時に用意されます。以下の2メソッドを付け加えてください。
User.php
public function setPasswordAttribute( $value ) { $this->attributes['password'] = Hash::make( $value ); } public function roles() { return $this->belongsToMany( 'Role' ); }
setPasswordAttributeメソッドは、保存時に毎回ハッシュをかけるのは面倒なため、passwordフィールドを設定する時は、毎回自動的にハッシュされるように、設定しています。
rolesメソッドはリレーションの名前でもあります。どんな名前でもメソッド名として使用できますが、多対多関係の場合、相手のテーブル名と同じ、複数形がしっくりするでしょう。
このメソッドでは、相手のモデル名を指定し、belongsToManyメソッドを返します。ポイントとして、rolesはリレーション名でもあり、関係付の定義では、相手のモデル名(クラス名)を指定することを押さえておきましょう。
続いて、roleモデルです。これは短いですので、全コードを紹介します。
Role.php
<?php class Role extends Eloquent { public function Users() { return $this->belongsToMany( 'User' ); } public function Permissions() { return $this->belongsToMany( 'Permission' ); } }
rolesテーブルは、usersテーブルとpermissionsテーブルに対し、それぞれ多対多の関係を持つため、二つのリレーションを定義しています。
Permission.php
<?php class Permission extends Eloquent { public function Roles() { return $this->belongsToMany( 'Role' ); } }
permissionsテーブルは、rolesテーブルに対してのみ関係付けを持ちますから、定義は一つだけです。
続き: