Laravel5.1.11で実装されたAuthorization(gate)を試す

##追記(2016/2/10)

Laravel5.2では、MultiAuthが標準で導入されました。
どうやら、本機能は、config/auth.phpでdefault（標準ではweb)に設定されたguardのみで有効になるようです。
それ以外のguardでの認証は、「認証されてないユーザー」と同様の扱いになるようです。

つまり、adminsテーブルを利用して、管理画面の機能出し分けを行ない、usersテーブルでユーザー向けのコンテンツを出し分けるということが出来ないようです。

なお、guestやauthなどのミドルウエアは、下記のようにguardを判定する仕組みが実装されており、

```php
public function handle($request, Closure $next, $guard = null)
{
    if (Auth::guard($guard)->guest()) {
        if ($request->ajax()) {
            return response('Unauthorized.', 401);
        } else {
            return redirect()->guest('login');
        }
    }

    return $next($request);
}
```
guest:users,guest:adminsなどと、定義したguardを指定することができます。
現在、gateにて対象とするguardを指定する方法を模索中。知ってる人いれば教えて下さい。

##やりたいこと

Laravel5.1.11から、[Authorization機能](http://laravel.com/docs/master/authorization)（権限管理機能？）が導入されたみたいなので試してみます。
要は、「全員ユーザー閲覧OKだけど、更新はAdminだけ」というような制御が簡単に行えるようになったということみたいです。

特にbladeで@canが使えるようになっており、

```html
@can('if_admin')
hello admin
@else
hello user
@endcan
```
というような記述ができるようになっているので、それを試してみたい。

>ややこしいのですが、今まであったのが、Authentication（認証・ログイン）で、今回追加されたのが、Authorization（権限管理）です。


##前提認識

まず、Authorizationを使えば、ユーザー毎に権限制御ができますが、当然のことながら、Laravelの認証機構にてログインしているユーザーが対象になります。

あと、権限をモデルに依存せず（全体的に）制御する方法と、モデルに依存させて制御する方法があるようです。今回は、全体的？に制御する方法を見てみます（私の用途はほとんどこれで足りるので）。
モデルに依存させるとは、Userモデルの更新は許可とか、Postモデルの更新は非許可とかという意味です。

あと、adminとuserで分けたい！といっても、Laravelには、そもそも、それを判別する仕組みがないので、そこは独自に実装が必要になります（admin,userという利用シーンでなくても、投稿したユーザーのみ、記事を編集可能とか）。

####Laravel標準のAuthorizationの利用シーンまとめ
* LaravelのAuthentication機構でログインしたユーザー
* 全体的に権限を管理する方法（モデル非依存）がある
* モデルと合わせて権限を管理する方法がある
* 権限管理の元データとなるadmin,user等の区別は独自実装する必要がある

##前提

ここでは、adminとuserでのコンテンツ出し分けを試してみたいと思います。
adminとuserの区別は、Userテーブルにroleを設定し、そこにadminなら"admin"を。userなら"user"と設定することで区別することにします。詳細は、[こちら](http://qiita.com/zaburo/items/2ebc725e29657206d7d9)をどうぞ。

##試してみる

###最初にView(blade)から

設定した権限はいろんなところで利用できますが、今回はbladeによる出し分けがメインなので、viewから作ってみます。
こんな感じ。これを、hello.blade.phpとしてViewに保存しておきます。

```html
<h3>Authorization Test</h3>

@can('index')
Hello Login Users.<br>
@endcan

@can('update')
Hello Admin Users.<br>
@endcan
```

期待する動きは、adminの時は"Hello Admin Users."（と、Hello Login Users)が、その他の（ログイン済）ユーザーの時は"Hello Login Users."と表示されることです。実際の利用シーンとしては、更新はadminのみ、閲覧は誰でも可というようなイメージでしょうか。

@can('hoge')のhogeの部分は、任意に設定していいようです。また、後で出てくるPolicy設定の際、$ability変数として利用されます。

>なお、ログインしていないユーザーは、そもそも@canの判断対象にならないようです。

###ルートの設定

いちおう、上記bladeを表示するためのルートを記述しておきます。

```php
Route::get('hello',function(){

	if(Auth::check()){
		return view('hello');
	}else{
		return "You need login.";
	}

});
```

###ポリシーの設定

Policyは、モデル依存の場合は個別にPolicyファイルを設定し、それをAuthServiceProviderに登録するようですが、全体なので、app/Providers/AuthServithProvider.phpのboot()に直接記述します。

~~なお、全体に適用したいPolicyは、AuthServiceProvider.phpの$gate->before()に記述するようです。~~

```php
<?php

namespace App\Providers;

use Illuminate\Contracts\Auth\Access\Gate as GateContract;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

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

    /**
     * Register any application authentication / authorization services.
     *
     * @param  \Illuminate\Contracts\Auth\Access\Gate  $gate
     * @return void
     */
    public function boot(GateContract $gate)
    {
        parent::registerPolicies($gate);
        
        //index（だれであれ、treuを返す）
        $gate->define('index',function($user){
            return true;
        });
        
        //update（ユーザーのroleがadminならtreu）
        $gate->define('update',function($user){
            if($user->role=="admin"){
                return true;
            }
        });
    }
}
```

なお、$gate->before()を利用して、下記のように書くこともできます。

```php
        //ここから追加
        $gate->before(function($user,$ability){

            if($ability=="index"){
                return true;
            }

            if($ability=="update"){

                if($user->role=="admin"){
                    return true;
                }
            }
        });
```

$userは、ログイン済のユーザー（のインスタンス）が、$abilityには、@can等を利用した際の添字？@can('hoge')のhogeの部分が渡されるようです。なので、ここでは、abilityの値によって、まず分岐させ、その後、adminかどうかの判断をしています。

ルートやログイン自体の設定が正しく実行されていれば、これだけの処理で表示の出し分けができます。