
九保すこひです(フリーランスのITコンサルタント、エンジニア)
さてさて、以前公開した「シンプル!Laravelで「権限つき」ログインさせる方法」では、ユーザーごとにアクセスできるページを決め、権限が無い場合は強制的にリダイレクトするというテクニックを紹介しました。
このテクニックを使えば、とてもシンプルにユーザータイプでアクセスページを分けることができます。ただ、アクセスではなく実行権限となると話は少し違ってきます。
例えば、
- 社長だけがデータ削除できる
- 社員は変更が可能
- アルバイトは見るだけ
というような、より細かい権限をつけたい場合です。
しかし、そこは人気フレームワークのLaravelです。
実は、このようなより複雑な実行権限をつけることができるLaravel Gate
という機能を標準搭載しているんですね。
そこで!
今回はこのLaravel Gate
を使って役職ごとに実行権限をつける実例を紹介します。ぜひ参考にしてみてくださいね。
※ 開発環境: Laravel 5.7
目次 [非表示]
やりたいこと
今回は以下3つのユーザータイプがある会社やお店のウェブサイトだと考えてください。
- 社長
- 従業員
- アルバイト
そして、これらのユーザーがアクセスできる「業務連絡」ページがあるとして、ここに次の実行権限をつけることにします。
- 社長 ・・・ 閲覧、追加、変更、削除
- 従業員 ・・・ 閲覧、追加、変更
- アルバイト ・・・ 閲覧
では実際に開発していきましょう!
テストデータをつくる
まずは、次のコマンドでLaravelでログイン機能が使えるようにします。
php artisan make:auth
そして、作成されたマイグレーションCreateUsersTable.php
を開いてrole
フィールドを追加します。
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email')->unique();
$table->string('role'); // ユーザータイプ
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
続いて、テストデータを追加するUsersTableSeeder
を作ります。
php artisan make:seed UsersTableSeeder
作成されたUsersTableSeeder.php
を開いて中身を次のように記述します。
public function run()
{
$users = [
[
'name' => '社長',
'role' => 'president',
'email' => 'president@example.com'
],
[
'name' => '従業員',
'role' => 'employee',
'email' => 'employee@example.com'
],
[
'name' => 'アルバイト',
'role' => 'part_timer',
'email' => 'part_timer@example.com'
]
];
foreach ($users as $user) {
\App\User::create([
'name' => $user['name'],
'email' => $user['email'],
'role' => $user['role'],
'password' => bcrypt('xxxxxxxx')
]);
}
}
次に忘れてはいけないのが、このUsersTableSeeder
を有効にするためのDatabaseSeeder.php
への登録です。
<?php
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
public function run()
{
$this->call(UsersTableSeeder::class);
}
}
ではマイグレーションを実行してみましょう。
php artisan migrate:fresh --seed
DBテーブルこのようになりました。
Laravel Gateの実行権限をつくる
ではLaravel Gateを使って「やりたいこと」に書いた次の権限をつくっていきましょう。
- 社長 ・・・ 閲覧、追加、変更、削除
- 従業員 ・・・ 閲覧、追加、変更
- アルバイト ・・・ 閲覧
コードを書くのは、app/Providers/AuthServiceProvider.php
のboot()
内ですです。
Policyをつくる
権限が少なければ、そのまま次のようにAuthServiceProvider.php
に直書きしても構いません。
public function boot()
{
$this->registerPolicies();
Gate::define('delete-announcement', function ($user) {
return ($user->role == 'president'); // 社長だけ削除OK
});
}
ただ、Laravelには保守管理しやすいように実行権限を管理するPolicy
という機能がありますので、今回はこちらで実装します。
次のコマンドを実行してください。
php artisan make:policy AnnouncementPolicy
すると、app/Policies/AnnoucementPolicy.php
というファイルが作成されるので、このファイルを開いて次のようにします。
<?php
namespace App\Policies;
use App\User;
use Illuminate\Auth\Access\HandlesAuthorization;
class AnnouncementPolicy
{
use HandlesAuthorization;
/* 閲覧 */
public function view(User $user)
{
$user_types = [
'president', // 社長
'employee', // 従業員
'part_timer' // アルバイト
];
return (in_array($user->role, $user_types));
}
/* 追加 */
public function create(User $user)
{
$user_types = [
'president', // 社長
'employee' // 従業員
];
return (in_array($user->role, $user_types));
}
/* 変更 */
public function update(User $user)
{
$user_types = [
'president', // 社長
'employee' // 従業員
];
return (in_array($user->role, $user_types));
}
/* 削除 */
public function delete(User $user)
{
return ($user->role == 'president'); // 社長だけOK
}
}
やっていることは、それぞれ$user->role
の中身をチェックしてreturn
しているだけです。
では、AuthServiceProvider.php
で、AnnouncementPolicy
を登録しましょう。
public function boot()
{
$this->registerPolicies();
Gate::resource('announcements', 'App\Policies\AnnouncementPolicy');
}
ちなみにGate::resource()
は、以下4つの権限を一気に作ってくれるショートカットの書き方です。
- view
- create
- update
- delete
そのため、上のコードは次のコードと同じになります。
お好みで使い分けてください。
Gate::define('announcements.view', 'App\Policies\AnnouncementPolicy@view');
Gate::define('announcements.create', 'App\Policies\AnnouncementPolicy@create');
Gate::define('announcements.update', 'App\Policies\AnnouncementPolicy@update');
Gate::define('announcements.delete', 'App\Policies\AnnouncementPolicy@delete');
実行権限を設置する
では、実際に作成した権限を設置するテストコードを作ってみましょう。
$user = auth()->loginUsingId(1);
/* 閲覧 */
if(Gate::allows('announcements.view', $user)) {
echo '閲覧できます。';
} else {
echo '閲覧できません!';
}
/* 追加 */
if(Gate::allows('announcements.create', $user)) {
echo '追加できます。';
} else {
echo '追加できません!';
}
/* 変更 */
if(Gate::allows('announcements.update', $user)) {
echo '変更できます。';
} else {
echo '変更できません!';
}
/* 削除 */
if(Gate::allows('announcements.delete', $user)) {
echo '削除できます。';
} else {
echo '削除できません!';
}
まず1行目はユーザー(ここでは社長ユーザー)を取得しています。
そして、Gate::allows()
を使って権限が「ある人だけ」をチェックして分岐させています。もし、逆に権限が「ない人だけ」をチェックしたい場合はGate::denies()
を使ってください。
実行結果
では実際にどのようになるか各ユーザーの実行結果を見てみましょう。
社長の場合
従業員の場合
アルバイトの場合
Bladeで権限がある人にだけリンクを表示する
Laravel Gate
は通常のPHPコードだけでなく、テンプレート・エンジンBlade
の中でも利用することができます。
例えば、「業務連絡の権限がある人にだけリンクを表示する」といった使い方です。
では、実際に見てみましょう。
<!-- 業務連絡 -->
@can('announcements.view', auth()->user())
<a href="/announcements">業務連絡</a>
@endcan
使い方は先ほどのallows()
とほぼ同じで@can
を使います。(逆は@cannot
)
これをLaravelに始めから用意されているwelcom.blade.php
で実行すると次のようになります。
まずはログインしていない状態です。
何も表示されていません。
次にログインして表示したものです。
業務連絡というリンクが表示されました。
もちろん、権限をもっていなければ、ログインしていても表示されないパターンもあります。
お疲れ様でした!
おわりに
ということで、今回はLaravel Gate
を使って実行権限を管理する方法をご紹介しました。
特に会社組織のサイトなど、ユーザータイプが多い場合に重宝するのではないでしょうか。また、ユーザーが仮登録しかしていない場合は投稿を拒否したり、投稿した本人だけ変更/削除できるようにするという設定もできます。
なお、実行権限をPolicy
として分割管理しておけば以前使ったものを再利用できますので、その後の開発効率がグンっとあがるというメリットもあります。
ぜひ活用してみてはいかがでしょうか。
ではでは〜!