目次
Laravelの記事一覧は下記
PHPフレームワークLaravelの使い方
Laravelバージョン
動作確認はLaravel Framework 7.19.1で行っています
認可
簡単に言うと
認証はアクセスしてきているユーザーが誰なのかを認識するもの
認可はアクセスしてきたユーザーに操作を許可するかどうかを判定するもの
です
Gateを使った認可
簡単に言うと
真偽値を返す関数(Gate)を作っておき、それを簡単に呼び出せるようにしておくようなものです
前提条件
eclipseでLaravel開発環境を構築する。デバッグでブレークポイントをつけて止める。(WindowsもVagrantもdockerも)
本記事は上記が完了している前提で書かれています
プロジェクトの作成もapacheの設定も上記で行っています
Laravelの認証(web画面)
本記事は上記記事でLaravelの認証が実装されている前提で書かれています
認可に使うカラム追加
(1) マイグレーション作成
コマンドラインで
cd sample
php artisan make:migration add_rank_to_users --table=users
xdebugの設定をしているとeclipseが実行していいですかというプロンプトを出すのでOKを押します
eclipseプロジェクトを右クリック→リフレッシュ
/sample/database/migrations/xxxx_xx_xx_xxxxxx_add_rank_to_users.phpが現れます
xxxx_xx_xx_xxxxxx_add_rank_to_users.php修正
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddRankToUsers extends Migration
{
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->integer('rank')->default(1);
});
}
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('rank');
});
}
}
usersテーブルにrankカラムを追加するマイグレーションです
今回はrankというカラムをつくり、その値によってGateを使った認可が行われるサンプルを作っていきます
(2) マイグレーション実行
コマンドラインで
php artisan migrate
xdebugの設定をしているとeclipseが実行していいですかというプロンプトを出すのでOKを押します
usersテーブルにrankカラムが追加されます
(3) Model修正
/sample/app/Models/User.php修正
‥‥
protected $fillable = [
'name', 'email', 'password', 'rank',
];
‥‥
$fillableプロパティにrank追加
Gate作成
/sample/app/Gatesフォルダ作成
/sample/app/Gates/UserGate.php作成
<?php
namespace App\Gates;
use App\Models\User;
class UserGate
{
public function __construct()
{
}
public function rank(User $user, int $rank){
if ($user->rank >= $rank) {
return true;
}
return false;
}
}
rankというメソッドをつくりました
Gateのメソッドの第一引数は必ず、ユーザーインスタンスになります
第二引数以降を定義するかどうかは任意です
第二引数が無くてもいいですし、第三引数、第四引数が定義されていてもいいです
Gateの登録
/sample/app/Providers/AuthServiceProvider.php修正
‥‥
public function boot()
{
$this->registerPolicies();
Gate::define('UserGate-Rank', 'App\Gates\UserGate@rank');
}
‥‥
Gate::define('UserGate-Rank', 'App\Gates\UserGate@rank');追記しました
これでLaravelアプリケーションの中でGateを簡単に呼び出せるようになります
Controller修正
(1) use文追記
use Illuminate\Support\Facades\Gate;
use App\Models\User;
(2) /sample/app/Http/Controllers/SampleController.phpにgate1メソッド、gate2メソッドを追記
public function gate1()
{
return view('sample.gate1');
}
public function gate2(Request $request)
{
$data = [];
$rank = $request->input('rank');
if (Gate::denies('UserGate-Rank', [$rank])) {
return redirect('sample/gate1')->withInput();
}
$id1user = User::find(1);
if(!is_null($id1user) && Gate::forUser($id1user)->allows('UserGate-Rank', [$rank])){
$data['user1_allows'] = 'user1のランクは' . $rank . '以上';
} else {
$data['user1_allows'] = 'user1のランクは' . $rank . '以下';
}
return view('sample.gate2', $data);
}
・AuthServiceProviderで登録したGateを使うには
Gate::allowsや、Gate::deniesで呼べます
第一引数にAuthServiceProviderのbootメソッドで実行したGate::defineの第一引数を与えます。すると、Gate::defineの第二引数に渡したクラス@メソッドが実行されます
Gate::allowsや、Gate::deniesに渡した第二引数の配列は展開されGateの第二引数、第三引数……となります
・Gate::allowsはGateが返す真偽値がそのまま戻り値になります。Gate::deniesはGateが返す真偽値が逆になります
・Gate::allowsはログインしていないユーザーの場合falseを返します。Gate::deniesはログインしていないユーザーの場合trueを返します。Gateの処理は関係なくなります。
もし、ログインしていないユーザーでもGateを実行したい場合は下記のようにGateに定義してメソッドの第一引数のタイプヒントにクエスチョンマークを付けてください
public function rank(?User $user, int $rank){
・Gate::allows、Gate::deniesの場合、Gateの第一引数はAuth::user()になります
・Gate::forUser()->allows、Gate::forUser()->deniesの場合、Gateの第一引数はGate::forUserに与えた引数になります
実際にGateを使う場合は
MiddlewareでGate::deniesを呼び出し、結果によってredirectしたり、
Ruleクラスの中で呼び出すことが多いと思います
(2) /sample/routes/web.phpに下記を追記
Route::get('sample/gate1', 'SampleController@gate1');
Route::get('sample/gate2', 'SampleController@gate2');
viewの作成
(1) /sample/resources/views/sample/gate1.blade.phpファイル作成
<html>
<head>
<title>sample</title>
</head>
<body>
<form action="{{ url('sample/gate2') }}" method="get">
<div>rank<input type="text" name="rank" value="{{ old('rank') }}"></div>
<input type="submit" >
</form>
</body>
</html>
(2) /sample/resources/views/sample/gate2.blade.phpファイル作成
<html>
<head>
<title>sample</title>
</head>
<body>
<div>{{$user1_allows}}</div>
<div>
@can('UserGate-Rank', [5])
ログインユーザーのランクは5以上
@elsecan('UserGate-Rank', [4])
ログインユーザーのランクは4以上
@else
ログインユーザーのランクは3以下
@endcan
</div>
<div>
@cannot('UserGate-Rank', [2])
ログインユーザーのランクは2未満
@elsecannot('UserGate-Rank', [3])
ログインユーザーのランクは3未満
@else
ログインユーザーのランクは3以上
@endcannot
</div>
</body>
</html>
blade内でGateを使うにはcanやcannotで呼び出せます
@can
はGate::allowsと同じです
@cannot
はGate::deniesと同じです
@can
や@cannot
を使うことで、更新ボタンを特定のユーザーにだけ表示させたり、または、逆に非表示にしてりできます
動作確認
usersテーブルのrankカラムの値を適当な値にupdateします
update users set rank = 4;
ログインします
http://localhost/laravelSample/
右上のLOGINからログインします
http://localhost/laravelSample/sample/gate1
rankを4にupdateしてので
5以上の値を入力して送信ボタンをクリックするとgate1にリダイレクトされ先に進めないと思います
4以下の値を入力して送信ボタンをクリックするとgate2に遷移できます
今回はサンプルのため入力値のエラーチェックを一切行っていないので、gate1の入力欄には数値を入れてください。数値でない場合、制御されていない型エラーになります
実際にシステムを開発するときはちゃんとエラーチェックを入れましょう
エラーチェックの実装の仕方は下記に書いてあります
Laravelで入力値エラーチェック(validate)を実装する