速習Larave3(その10)、ルートの保護とエラーページ

タグ: Laravel3  

せっかく認証を取り入れましたが、上手く活用していません。十分に活用しましょう。

Webアプリでなぜ認証が必要かと言えば、特定のページは一般の人に見せたくないからです。ルートを保護するという事ですね。

Laravelでログインしている人だけ、特定のルートのページを使用できるようにするには、authフィルターを使用します。

では、どのルートを保護すれば良いのでしょうか?今まで作成した中でちょっと考えてみましょう。

するとどうやら、削除と追加/更新を保護すれば良いようです。勝手に記事を消されたり、中身を書き換えられたり、むふふな記事を大量に書かれては、困ってしまいます。

とりあえず削除のルートだけに入れてみましょう。

// 記事削除
//  フォーム表示
Route::get('/post/delete/(:num)', array( 'as' => 'post-delete', 'before' => 'auth', 'uses' => 'post@delete' ));
//  フォーム処理
Route::post('/post/delete/(:num)', array( 'as' => 'post-delete', 'before' => 'csrf|auth', 'uses' => 'post@delete' ));

これで良し。フォーム処理のルートに対し、beforeフィルターを2つ指定しています。その時は縦棒で区切って指定します。伝統的にフィルターは縦棒でつなげるものですからね。

しかしまあ、もうちょっと工夫してかけます。とりあえず、ルートの定義の部分をご覧ください。

/*
 * ルーティング定義
 */

// トップページ:一覧表示
Route::get('/', array( 'as' => 'post-index', 'uses' => 'post@index' ));

// 記事表示
Route::get('/post/(:num)', array( 'as' => 'post-show', 'uses' => 'post@show' ));

// ログイン
Route::get('/login', array( 'as' => 'login', 'uses' => 'auth@login' ));
Route::post('/login', array( 'as' => 'login', 'before' => 'csrf', 'uses' => 'auth@login' ));

// ログアウト
Route::get('/logout', array( 'as' => 'logout', 'uses' => 'auth@logout' ));

// ユーザー認証が必要な管理者領域
Route::group(array( 'before' => 'auth' ),
    function() {
        // 記事追加/編集
        //  フォーム表示
        Route::get('/post/edit/(:num?)',
            array( 'as' => 'post-edit', 'uses' => 'post@edit' ));
        //  フォーム処理
        Route::post('/post/edit/(:num?)',
            array( 'as' => 'post-edit', 'before' => 'csrf', 'uses' => 'post@edit' ));

        // 記事削除
        //  フォーム表示
        Route::get('/post/delete/(:num)',
            array( 'as' => 'post-delete', 'uses' => 'post@delete' ));
        //  フォーム処理
        Route::post('/post/delete/(:num)',
            array( 'as' => 'post-delete', 'before' => 'csrf', 'uses' => 'post@delete' ));
    });

同じフィルターを適用したいルートはグループにまとめられます。今回は認証が必要なルートをグループ化することで、ルートも読みやすくなりました。そう、可読性も大切ですよ。

これできちんと動作するか確認してください。トップページから、ログインしている時としていない時の両方で、削除と更新のリンクをクリックしてください。

authフィルターの定義も同じroutes.phpの中で行われています。

Route::filter('auth', function() {
        if ( Auth::guest() )
            return Redirect::to_route('login')
                ->with('message', 'ログインが必要です。');
    });

少し変えてあります。デフォルトのコードにメッセージを付けてリダイレクトするようにしています。なにせ、元々のコードは黙ってログインページにリダイレクトするだけですからね。

あと、Redirect::toRedirect::to_route()に変更しました。toはURLやURIに対して使用します。to_routeはルートの名前を指定します。せっかく名前をルートにつけているのですから、使わなくちゃ損ですよ。

何に役に立つかって?例えばこの場合でしたら、ログインへのURIはloginで分かりやすですよね。でも例えばsuper-login-48などに変えると、このURIを知っている人しかログインできなくなりますよね。ログインのURIが分かっているとチャレンジする不届き者やら出てきますからね。ルート名を指定しておけば、そうしたURIの変更時にアチラコチラのコードをいじる必要が無くなるわけです。ルートの定義のURIパターンだけを変更すれば済みます。

あと新しい事柄は、認証のチェックで使用されている'Auth::guest()'です。これはログインしていない時にtrueになります。

これできちんと動作するか確認してください。トップページから、ログインしている時としていない時の両方で、削除と更新のリンクをクリックしてください。

よしよし。上手く動作していますね。けど、ちょっと引っかかります。よく考えたら、ログインしていない人にリンクを見せなきゃ、もっと良いですよね。

これは一覧ページのビューの変更だけで、可能ですよ。index.blade.phpを修正してください。

@layout('template')

@section('title')
一覧表示
@endsection

@section('content')
<style>
    .pagination li {
        display: inline;
        margin: 0 5px;
    }
</style>
<table>
    <tr>
        <th>タイトル</th>
        <th>作成日</th>
        @if( Auth::check() )
            <th>更新</th>
            <th>削除</th>
        @endif
    </tr>
    @foreach($posts as $post)
    <tr>
        <td>{{ HTML::link_to_route('post-show', $post->title ,array($post->id)) }}</td>
        <td>{{ $post->created_at }}</td>
        @if( Auth::check() )
            <td>{{ HTML::link_to_route('post-edit', '✜', array($post->id)) }}</td>
            <td>{{ HTML::link_to_route('post-delete', '✖', array($post->id)) }}</td>
        @endif
    </tr>
    @endforeach
</table>
{{ $link }}
@endsection

Auth::check()を使用して、ログインしている場合のみ、表示するように変更しました。このメソッドはAuth::guest()の逆でして、ログインしている場合のみtrueになります。

これで一覧ページを見てください。ログインしていないときはポスト名と作成日時が表示され、ログインすると更新、削除が表示される便利な一覧ページになりました。CMSのようですね。

せっかく、routes.phpを開いているので、もうひと工夫しましょう。エラーページです。デフォルトのエラーページは英語ですし、しかもデザインが通常のページと異なっています。みっともないですね。これをどうにかしましょう。

元々のエラーページはviews/errorフォルダーの下に、ステータスコードと同じ名前のPHPファイルに記述されています。

そして、エラー時の処理はroutes.php内で記述されており、変更可能です。通常のビューページと同じように作成可能です。まず、404エラーページを作成しましょう。

views/error/404error.blade.phpを作成してください。

@layout('template')

@section('title')
404 ページが見つかりません
@endsection

@section('content')
<h2>404エラー</h2>
<h3>ページが見つかりません。</h3>
<p>お探しのページが見つかりません。</p>
<p>URLを指定した場合は、間違っていないかご確認ください。</p>
@endsection

ご覧の通り。Bladeだって使えちゃいます。内容は短めですよ。お好きに工夫してください。

ビューを出力しているだけですが、元々のエラーステータスコードはそのまま404で送られます。全くLaravelは苦労いらずですね。

あと、500ページは皆さんにお任せします。お好きに作成してください。エラー処理も修正する必要があることをお忘れなく。