16.Token機能

Token機能はStrutsなどでも採用されている機能で、リクエストパラメータ内に特定の文字列(Token)を埋め込んでおき、サーバのセッションコンテキスト内に保存されているTokenと照合することにより、2重送信の防止やページ遷移の保証などを行う機能です。

リクエストページ(token.vm)

Tokenを発行するページです。通常入力画面や確認画面などになります。

<html>
<body>
<form action="token.action">
<h3>Token</h3>
#tag (Token)
<input type="submit" value="実行">
</form>
<form action="token-session.action">
<h3>TokenSession</h3>
#tag (Token)
<input type="submit" value="実行">
</form>
</body>
</html>

入力フォーム内に#tag (Token)と書くだけです。なぜフォームが2つ有るかは次で説明します。

xwork.xml

 <action name="tokenInit" class="com.opensymphony.xwork.ActionSupport">
  <result name="success" type="dispatcher">
   <param name="location">/WEB-INF/vm/token.vm</param>
  </result>
 </action>
 <action name="token" class="com.opensymphony.xwork.ActionSupport">
  <interceptor-ref name="token"/>
  <result name="success" type="dispatcher">
   <param name="location">/WEB-INF/vm/token_ok.vm</param>
  </result>
  <result name="invalid.token" type="dispatcher">
   <param name="location">/WEB-INF/vm/token_ng.vm</param>
  </result>
 </action>
 <action name="token-session" class="com.opensymphony.xwork.ActionSupport">
  <interceptor-ref name="token-session"/>
  <result name="success" type="dispatcher">
   <param name="location">/WEB-INF/vm/token_ok.vm</param>
  </result>
  <result name="invalid.token" type="dispatcher">
   <param name="location">/WEB-INF/vm/token_ng.vm</param>
  </result>
 </action>

tokenアクションはtoken.vmを表示するだけです。
tokenとtoken2の違いは、interceptorがtokenかtoken-sessionだけです。
token_ok.vmとtoken_ng.vmについては表示するだけなので適当な内容のファイルを作ってください。

アクション:tokenの場合(interceptor:token)

tokenInitで表示される画面で実行を押した場合、最初のリクエストは正常に処理され、token_ok.vmの画面が表示されますが、token.actionをリロードしたりブラウザの戻るを押して実行ボタンを押すとresultとしてinvalid.tokenが返され、token_ng.vmの画面が表示されます。発行されていないTokenがリクエストパラメータで送られた場合やTokenが送られなかった場合もinvalid.tokenが返されます。

アクション:token-sessionの場合(interceptor:token-session)

最初のリクエストや、発行されていないTokenがリクエストパラメータで送られた場合やTokenが送られなかった場合はtokenと同様の動きとなりますが、リロードなどにより同じTokenで2回目のリクエストがあった場合は1回目のリクエストと同じ結果が出力されます。つまり、2回目以降のリクエストでもtoken_ok.vmの画面が表示されます。(ただし、Action内の処理は2回目は実行されません)
token-sessionインターセプタで1回目のリクエストの結果をセッションに保存して、同じTokenが来た場合はそれを返すだけにしているようです。

まとめ

2重押し防止のチェックとしてはtoken-sessionの方がユーザに優しいと思います。2回目のリクエストをエラーにされると1回目のリクエストが成功したかどうかもわからないためです。ただセッションにActionの情報を保存するためメモリの消費は増えるはずです。