page_adsence

2016年1月29日金曜日

Laravel4.2で入力->確認->完了の画面遷移を実装してみる。(CSRF対策もおまけで)

Laravelでフォームを作るとどんな感じになるのか試してみた。
CSRF対策と2重送信の防止をするという前提で作ってみました。

app/routes.phpを編集し、入力、確認、完了画面で実行するコントローラーとアクションを定義する。
入力画面に関してはCSRF対策用のフィルタは通さずに、確認、完了画面に関してはCSRF対策用のフィルタを通す様に記述しました。
CSRF対策用のフィルタ処理はapp/filters.phpに書いてあります。(Laravelが元々用意している機能)
$ vi app/routes.php
Route::get('/input', 'HomeController@input');
Route::group(array('before' => 'csrf'), function()
{
    Route::post('/confirm',  'HomeController@confirm');
    Route::post('/complete', 'HomeController@complete');
});

続いてアクション。
下記の3つのメソッドを追加。
$ vi app/controllers/HomeController.php
public function input()
{
    return View::make('input');
}

public function confirm()
{
    return View::make('confirm');
}

public function complete()
{
    Session::regenerateToken();

    // 登録処理

    return View::make('complete');
}
完了画面で遷移してきた段階で、Laravelが作っているCSRF対策用のトークンを再生成しています。
これは、このトークンを2重送信防止用にも使用しているため、こういった形をとっています。
CSRF対策だけならこういった対応は必要ないと思います。
結局、「Session::regenerateToken()」は_tokenという名前でトークンをセッションに保存しているので、1セッションで複数フォームを開いた場合、
先に送信した方は登録されるが、後で送信された方はトークンが一致せずにエラーになる。
こういう挙動を許すかどうかは、そのシステムの要件次第なので、使用時に判断してもらえればと思います。

最後にテンプレート。
入力画面
$ vi app/views/input.blade.php
{{ Form::open(array('url' => 'confirm')) }}
<table>
<tr>
<td>タイトル</td><td>{{ Form::text('title') }}</td>
</tr>
<tr>
<td>メッセージ</td><td>{{ Form::textarea('message') }}</td>
</tr>
<tr>
<td colspan="2">{{ Form::submit('内容を確認') }}</td>
</tr>
</table>
{{ Form::close() }}

確認画面
$ vi app/views/confirm.blade.php
{{ Form::open(array('url' => 'complete')) }}
<table>
<tr>
<td>タイトル</td><td>{{ Input::get('title') }}{{ Form::hidden('title', Input::get('title')) }}</td>
</tr>
<tr>
<td>メッセージ</td><td>{{ Input::get('message') }}{{ Form::hidden('message', Input::get('message')) }}</td>
</tr>
<tr>
<td colspan="2">{{ Form::submit('内容を登録') }}</td>
</tr>
</table>
{{ Form::close() }}
完了画面
$ vi app/views/complete.blade.php
complete!