Top / Struts / 同期トークンで二度押しなどをチェックする

WEB開発で必ずついて回るのが、Submitボタン二度押しや戻るボタンを押されるなど、勝手な画面遷移をされないような配慮です。Strutsでは同期トークンという機能でこれらの考慮をサポートしてくれます。

実際にサンプルで、ある画面でSubmitを二度押ししたとき、それを検知して二つ目のリクエストをエラーではじくという事を考えてみます。

同期トークンとは

同期トークンの機能とは以下の通りです。

  1. あるアクションで、サーバ上でユニークなID(以下、トークン)を生成し、返却するhtmlにhidden等で仕込んでおく
  2. そのアクションで、トークンはSessionにも格納しておく
  3. 次のリクエストにはhidden内のトークンが飛んでくる
  4. 次のアクションで、hiddenパラメタ内のトークンとSessionのトークンが等しいことを確認する
  5. 等しければ、正しいリクエストということで処理する。Session内のトークンを新しいモノに書き換え、hiddenで返すトークンもその新しいモノにする。等しくなければ、正規のリクエストではないということで、エラー処理する。
  6. 以下繰り返し。

この中で、トークンの生成、トークンチェック、hiddenにトークンを書き出す、などはStrutsが自動でやってくれますので、使う側はトークンをチェックするメソッドをアクションクラスに記述したり、エラー処理だけをやっておけばよいと言うことですね。ラクチンです。

やってみる

流れ

index.do -> IndexAction -> index.jsp -> double.do -> DoubleAction -> success.jsp

という流れのサンプルです。

ソース

セッションにトークンをセット

IndexAction?でSessionにトークンをセットしています。トークンを生成してSessionにセットするメソッドは

org.apache.struts.action.Action#saveToken

です*1*2

JSPのhiddenにトークンをセット

index.jspではformを使ってSubmitしていますが、出力されるhtmlには自動的にhiddenタグが挿入されます。具体的にはSubmitのformは

<html:form method="post" action="/double" >
  <html:submit />
</html:form>

としているだけなのですが出力されるhtmlは

<form id="hogeForm" method="post" action="/strutsExamples/double.do">
  <div><input type="hidden" name="org.apache.struts.taglib.html.TOKEN" 
         value="612326e14b3ce599284543e2246f170b" /></div>
  <input type="submit" value="Submit" />
</form>

となります。あるキー値でhiddenにトークンがセットされています*3

次のリクエストで、サーバでトークンのチェック

さてこれでsessionにトークンがセットされ、さらにhtmlのhiddenにトークンがセットされました。次のリクエストを受けるアクション(DoubleAction?)では

synchronized (session) {
    tokenValid = isTokenValid(request);
    saveToken(request);
}
if (!tokenValid) {
    StringBuffer buffer = new StringBuffer();
    buffer.append("tokenチェックエラー");
    errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
            new String(buffer), false));
    saveErrors(request, errors);
}

となっています。

isTokenValid(request);

がSessionのトークンとhiddenのトークンをチェックするメソッドです。で、次の

saveToken(request);

で再度トークンを書き換えています。

isTokenValid?(request)はスレッドセーフですが、トークンを変更するまでスレッドセーフでなくてはいけないので、sessionインスタンスのモニタを取得して処理しています*4

Formでなく<html:link />の場合

上の例のように<html:form />タグの場合は自動でhiddenタグが挿入されトークンがPostされましたが、<html:link />タグなどの場合は

<html:link action="/double" transaction="true">リンク</html:link>

としてtransaction属性をtrueに指定します。transaction属性を指定すると

http://localhost:8080/strutsExamples/double.do
  ?org.apache.struts.taglib.html.TOKEN=f8e8901ab4cc126a148fe3d46d5596e7

とパラメタにトークンが設定されます。ちなみにこのtransaction属性はデフォルトはfalseなので、トークンを送信したい場合は明示的に指定してあげる必要があります。

サンプル。

この記事は

選択肢 投票
おもしろかった 264  
そうでもない 36  

Top / Struts / 同期トークンで二度押しなどをチェックする

現在のアクセス:123609


*1 中ではsessionIdをMD5でハッシュして、更に現在時刻でハッシュしているみたいです
*2 Sessionにセットされるときのキー値は"org.apache.struts.action.TOKEN"です。この定数値はorg.apache.struts.Globals.TRANSACTION_TOKEN_KEYで取得可能です。
*3 hiddenの定数値"org.apache.struts.taglib.html.TOKEN" はorg.apache.struts.Globals.TOKEN_KEYで取得可能です。
*4 スレッドセーフなメソッドを用意しておいてくれてもいいような、、、

トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS