セッションタイムアウト周りの実装

タイトルの通りではあるんだけど、ベストプラクティスがわからない

確実にアンチパターンに近い気がする

conf.routes

GET / controllers.HogeController.index
GET /index controllers.HogeController.errorIndex

みたいにしてる

viewテンプレートは

index.scala.html

<input type="submit" > 開始

エラー側

errorIndex.scala.html

<div class="error">エラー内容</div>
@index()

みたいな感じ。

なにが正しいのかわからない・・・

画面側からはセッションがタイムアウトしてないかをチェックして、アウトしていたら

/index にリダイレクト投げてるだけ

これで最初の画面に戻して、セッションを再取得して最初からアプリ処理をスタートさせてる。

こういうときのベストプラクティスが知りたい。

PlayFrameworkでPOSTが403で返ってきた(CSRFの話)

前回はセッションとキャッシュ周り

今回はPOST送信時の画面遷移でCSRFフィルタに引っかかってエラーになるようだった

やったことは以下の2点

  • フォームテンプレート+CSRFフォームフィールドを追加
  • リクエストヘッダを追加

順番に。

1つ目。

フォームテンプレート+CSRFフォームフィールドを追加

これは単純で

<form action="/pick1" method="POST"> となっていたものを

@form(routes.PickController.pick()) {

に変更。直下にCSRF用のフォームフィールドを追加

結果としてこうなる

@form(routes.PickController.pick()) {
    @CSRF.formField

これだけだとエラーになってしまったので、調べてみるとリクエストヘッダが必要と。

2つ目。リクエストヘッダを追加

これは各テンプレート(htmlファイルとか)の先頭とかに書いている@()の後ろに(implicit req: RequestHeader)を追加する

これでリクエストヘッダの情報と合わせてCSRFトークンチェックとかはフレームワーク側でやってくれるのであんまり気にしないで良くなったはず。

Playframework の セッションとかキャッシュ周り

相変わらず2pickシミュレータを作成中。

セッション周りとキャッシュ周り。

PlayFrameworkは基本的にセッションを自動で発行してくれてる(デフォルトでPLAY_SESSIONというcookie名)

だけど、Pickを開始するタイミングなり、最初の入口で一度リセットかけてセッションを再発行することで、前回の実行結果とかを引き継がないようにしたい

で、セッションを発行するときUUIDを使ってキャッシュもしておくということをしたい

セッションをはって、そのセッション内のデータをキャッシュしておくという使い方。

※ これが正しいかどうかは要検証。ひとまずはこれでやる

なので、これを参考に実行。 qiita.com

公式ドキュメント的にはこれwww.playframework.com

まずはbuild.sbtのlibraryDependenciesに以下を追加

  • ehcache
  • cacheApi

今回は同期したいのでplay.api.cache.SyncCacheApiを使う。

開始画面へクライアントがアクセスしたタイミングで一度セッションリセットをしたいのでこんな感じ

  def index() = Action { implicit request: Request[AnyContent] =>
    CacheUtil.deleteSessionUser(cache, request.session.get("sessionKey"))
    Ok(views.html.index()).withNewSession
  }

一度セッションクリアして、その上で新しいセッションを作成するようにして、次の画面で設定するということをする。

SyncCacheApiをInjectに失敗したりしていたが、build.sbtを見直したり、何度か sbt runをやり直してたら問題なくなった。

何がいけなかったのがそこだけわかっていない。

あと、テストの引数を追加する必要がある

※ Controllerの引数にキャッシュが追加されたので

こんな感じで追加

      val cache = app.injector.instanceOf[SyncCacheApi]
      val controller = new IndexController(cache, stubControllerComponents())

CSRFも少しハマったので次はその周りの話を書いていく