3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Laravelで認可(Gate)

Last updated at Posted at 2020-07-25

目次

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修正

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修正

User.php
‥‥
    protected $fillable = [
        'name', 'email', 'password', 'rank',
    ];
‥‥

$fillableプロパティにrank追加

Gate作成

/sample/app/Gatesフォルダ作成
/sample/app/Gates/UserGate.php作成

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修正

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ファイル作成

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ファイル作成

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)を実装する

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?