Laravel　認証と認可

#はじめに
PHPUnitを実行していた時にPolicyの書き方がまずくthis action is unauthorized
というエラーが出て２時間ほど詰まっていました。
この件は無事解決したのんですが、調べていく内にLaravelにおいては認証と認可があるということに気づきました。
まったく意識せずにコードを書いていたので自身の知識定着を兼ねて２つの違いを確認していく。

#ざっくりとした違い

２つの違いについてはこちらの記事を参考にさせていただきました。わかりやすい！
[よくわかる認証と認可 ｜ DevelopersIO](https://dev.classmethod.jp/articles/authentication-and-authorization/ "認証と認可")

一部抜粋しますと
認証とは**`通信の相手が誰（何）であるかを確認すること`**
認可とは**`とある特定の条件に対して、リソースアクセスの権限を与えること`**

認可の相手が誰であるか？というのは身近なところで行くとマイナンバーカードとかの身分証ですね。
認証は電車の切符みたいなものです。相手が誰だろうと関係ありません、持ってさえいれば誰でも大丈夫です。

なんとなくわかったところでLaravelに話を戻すと
Laravelでは、認証が「Guard」、認可が「Gate/Policy」の3パターンあるのです。

#認証：Guard

```config/auth.php
    'guards' => [
        'guard-name' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
    ],
```

```route/web.php
Route::get('profile', function() {
})->middleware('auth:guard-name');
```

例としてはguardsを設定してそれをルートのmiddlewareで使うという感じですね。
Guardに設定されているユーザだけにアクセスを許可してます！

#認可 Gate Policy


Policyはある特定のモデルに対して行うアクション(作成、更新、削除、閲覧等）に関してアクセス制限を行うため、モデルごとに個別の独立したPolicyファイルを作成する。

Gateは”主に”特定のモデルに関連していないユーザのアクションに関してアクセス制限を行う時に使用する。
例えば管理者画面にアクセスできるユーザを制限させるといったことにGateを利用することができます。

どちらか一方を使うというよりは、場面ごとに使い分けるってことですね！

##Gate

ここのroleがadminかどうかで管理者を見分けていく。

```users.table
public function up()
{
    Schema::create('users', function (Blueprint $table) {
        $table->bigIncrements('id');
        $table->string('name');
        $table->string('email')->unique();
        $table->timestamp('email_verified_at')->nullable();
        $table->string('password');
        $table->string('role');
        $table->rememberToken();
        $table->timestamps();
    });
}
```

まずはGateから考えてゆく。
定義を行う時はbootメソッドの中にGateファサードのdefineメソッドを使って行う。
defineメソッドの第一引数にはアクセス制限を行う際に利用する任意の名前、第二引数にはクロージャ―を設定します。クロージャ―の処理ではtrueかfalseかを戻す。
今回の場合はroleがadministratorであるかどうかを判別する処理を記述し、roleがadministratorであればtrueを戻し、そうでなければfalseを戻しとる。

```AuthServiceProvider.php
namespace App\Providers;

use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
protected $policies = [
    'App\Post' => 'App\Policies\PostPolicy',
];

    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();


        Gate::define('isAdmin',function($user){

           return $user->role == 'administrator';
    
        });
    }
}
```

定義を行なっただけでは使えないので、、制限を行いたい箇所に追加でコードを記述していく！

##Bladeで行う制御

Gateの設定後にbladeファイルでアクセス制限を行う場合は、@canを利用する。

```
@can('isAdmin')
  // ユーザ一覧を表示するhtmlを記述
@else
<p>管理者のみユーザ一覧が表示されます。</p>
@endcan
```

@cannotにすれば反対になる！

##コントローラで行う制御


```UsersContoroller.php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\User;

use Gate;

class UserController extends Controller
{

	public function index(){

	    Gate::authorize('isAdmin');

	    $users = User::all();

	    return view('users.index',compact('users'));
	    
	}

}
```

結構直感的に理解できますね。
他にもallowを使うことができる

```UsersContoroller.php
public function index(){

    if(Gate::allows('isAdmin')){

		$users = User::all();

	}else{

		dd('ユーザ一覧にアクセスが許可されていないユーザです。');

	}

	return view('users.index',compact('users'));
    
}
```

ちなみにauthorizeメソッドを使用した場合は、roleがadministratorでない場合は403のAuthorizationExceptionが返される。

##Policyを用いた制限

ターミナル　`$ php artisan make:policy HogePolicy --model=Post`で作成可能。
--modelオプションはそのモデルに関するPolicyを作成するってこと。
つけなくてもおけい。
今回はPostPolicyを作成してみていく。

```PostPolicy.php
namespace App\Policies;

use App\User;
use App\Post;
use Illuminate\Auth\Access\HandlesAuthorization;

class PostPolicy
{
    use HandlesAuthorization;
 
    /**
     * Determine whether the user can view the post.
     *
     * @param  \App\User  $user
     * @param  \App\Post  $post
     * @return mixed
     */
    public function view(User $user, Post $post)
    {
       
        return $user->id == $post->user_id;
  
    }
   
    /**
     * Determine whether the user can delete the post.
     *
     * @param  \App\User  $user
     * @param  \App\Post  $post
     * @return mixed
     */
    public function delete(User $user, Post $post)
    {
        return $user->id == $post->user_id;
    }

}
```

作成したPolicyの情報はAuthServiceProvider.phpに登録を行う必要がある。
登録を行うことでPostモデルとPostPolicyが紐づけられる！

```AuthServiceProvider.php
protected $policies = [
    'App\Post' => 'App\Policies\PostPolicy',
];
```

Policyは3つのやり方があるばい。
①authorizeメソッドを利用した制限
②canメソッドを利用した制限
③middleware(ミドルウェア)を利用した制限

##authorizeメソッドを利用した制限

```PostController.php
public function destroy(Post $post){

    $this->authorize('delete', $post);

    $post->delete();

　　 return redirect('/posts');

}
```

authorizeの最初に引数の’delete’がPostPolicy.phpファイル内に記述したdeleteメソッドを対応します。2番目の引数には、Postモデルの変数$postを指定している。

##canメソッドを利用した制限

```PostController.php
public function show(Post $post){

    $user = auth()->user(); //アクセスしているユーザ情報を取得

    if($user->can('view',$post)){

    	return view('posts.show',compact('post'));

    }else{

        dd('閲覧する許可がありません。');
    }

}
```

両者の違いは認証されなかった時に403ページが表示されるかされないか。

##middleware(ミドルウェア)を利用した制限

```
Route::get('/posts/{post}','PostController@show')->middleware('can:view,post');
```

ちなみにコントローラメソッドとポリシーメソッドは関係性を持ってて
コントローラーのshowメソッドは、Policyのviewメソッドと関連を持ってて、コントローラのshowメソッドの中でauthorizeメソッドを実行すると自動でPostPolicy.phpファイルのviewメソッドが実行される。
他のやつもね。

あと、コントローラーの__constructメソッドにauthorizeResourceメソッドを追加するとコントローラーの個別のメソッドでauthorizeメソッドを使わなくてもPolicyファイルで指定したメソッドが有効になる。

```PostController.php
class PostController extends Controller
{

	public function __construct(){
        $this->authorizeResource(Post::class);
	}
```

#まとめ
まあとりあえず
認証は**`通信の相手が誰（何）であるかを確認すること`** (Guard)
認可は**`とある特定の条件に対して、リソースアクセスの権限を与えること`** (Gate,Policy)

それぞれ定義してからbladeかcontrollerで使っていくと考えたら良いかなと思います。
習うより慣れろ！ですね。