#author("2023-08-11T07:13:09+00:00","","")
#author("2023-08-11T07:13:15+00:00","","")
// 下階層用テンプレート
#topicpath
----
//ここにコンテンツを記述します。
#contents
WEB開発で必ずついて回るのが、Submitボタン二度押しや戻るボタンを押されるなど、勝手な画面遷移をされないような配慮です。Strutsでは同期トークンという機能でこれらの考慮をサポートしてくれます。

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

**同期トークンとは [#n88a5573]
同期トークンの機能とは以下の通りです。

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

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


**やってみる [#ee906f33]

***流れ [#c64313a1]
 index.do -> IndexAction -> index.jsp -> double.do -> DoubleAction -> success.jsp
という流れのサンプルです。

***ソース [#c08839fb]
-IndexAction
 public ActionForward execute(ActionMapping mapping, ActionForm form,
     HttpServletRequest request, HttpServletResponse response)
     throws Exception {
   saveToken(request);
   return mapping.findForward("success");
 }

-index.jsp
 <?xml version="1.0" encoding="UTF-8" ?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
 <%@ page language="java" contentType="text/html; charset=UTF-8" %>
 <%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
 <%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
 <%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
 
 <%@page import="org.apache.struts.Globals"%>
 <html:html xhtml="true" lang="true">
 <head>
 <title>同期トークンの稼動確認JSP</title>
 <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
 <html:base />
 </head>
 <body>
 <html:form method="post" action="/double" >
   <html:submit />
 </html:form>
 <%=session.getAttribute(Globals.TRANSACTION_TOKEN_KEY) %>
 </body>
 </html:html>


-DoubleAction
 public ActionForward execute(ActionMapping mapping, ActionForm form,
      HttpServletRequest request, HttpServletResponse response)
      throws Exception {
   ActionMessages errors = new ActionMessages();
   HttpSession session = request.getSession();
   boolean tokenValid = false;
   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);
   }
 }



***セッションにトークンをセット [#n9e5325d]
IndexActionでSessionにトークンをセットしています。トークンを生成してSessionにセットするメソッドは
 org.apache.struts.action.Action#saveToken
です((中ではsessionIdをMD5でハッシュして、更に現在時刻でハッシュしているみたいです))((Sessionにセットされるときのキー値は"org.apache.struts.action.TOKEN"です。この定数値はorg.apache.struts.Globals.TRANSACTION_TOKEN_KEYで取得可能です。))。

***JSPのhiddenにトークンをセット [#m937a884]
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にトークンがセットされています((hiddenの定数値"org.apache.struts.taglib.html.TOKEN" はorg.apache.struts.Globals.TOKEN_KEYで取得可能です。))。

***次のリクエストで、サーバでトークンのチェック [#k368ed90]
さてこれで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インスタンスのモニタを取得して処理しています((スレッドセーフなメソッドを用意しておいてくれてもいいような、、、))。

**Formでなく<html:link />の場合 [#e1cadcc0]
上の例のように<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なので、トークンを送信したい場合は明示的に指定してあげる必要があります。


**サンプル。 [#kf462253]
-[[サンプルプログラム(ViewVC)>http://www.masatom.in/cgi-bin/viewvc.cgi/tags/V1.0.0_20080120_01/strutsExamples/?root=Others]]
-[[サンプルプログラム(Subversion)>https://www.masatom.in/svnsamples/repo/tags/V1.0.0_20080120_01/strutsExamples]]




この記事は
#vote(おもしろかった[275],そうでもない[37])
#vote(おもしろかった[276],そうでもない[37])
- その他のリンク系のタグは、rewriteタグがありますね。これもtransaction="true"をつけて制御します。 -- [[きの]] &new{2008-01-27 (日) 00:39:44};
- メイン画面と別にサブウィンドウでも更新する画面の場合ってトークンがずれてしまいますよね? -- [[yama]] &new{2011-03-02 (水) 13:07:06};
- auztxyMoZWaQ -- [[dzpntfpgxt]] &new{2012-07-16 (月) 10:44:19};
- test1 -- [[test]] &new{2015-07-15 (水) 09:11:21};
- 初めまして。下記の場合はどのようにすれば良いのでしょうか?フォームから送信した人に、トークンで期間限定のリンクを自動生成して返信、期間内であれば指定したページが見れて、期間外であれば404ページが表示される、というようにしたいのですが、 -- [[masaya]] &new{2016-09-20 (火) 04:58:48};
- 初めまして。フォームから送信した人に、期間限定のリンクを自動生成して送信し、期間内であれば指定したページが見れて、期間外であれば404ページが表示される、というようにする場合はどのようにすれば良いでしょうか? -- [[masa]] &new{2016-09-20 (火) 05:04:49};
- 初めまして。フォームから送信した人に、期間限定のリンクを自動生成して送信し、期間内であれば指定したページが見れて、期間外であれば404ページが表示される、というようにする場合はどのようにすれば良いでしょうか? -- [[masa]] &new{2016-09-20 (火) 05:06:35};
- 初めまして。下記の場合はどのようにすれば良いのでしょうか?フォームから送信した人に、トークンで期間限定のリンクを自動生成して返信、期間内であれば指定したページが見れて、期間外であれば404ページが表示される、というようにしたいのですが、 -- [[masaya]] &new{2016-09-20 (火) 05:08:31};
- 初めまして。フォームから送信した人に、期間限定のリンクを自動生成して送信し、期間内であれば指定したページが見れて、期間外であれば404ページが表示される、というようにする場合はどのようにすれば良いでしょうか? -- [[masa]] &new{2016-12-18 (日) 16:53:53};
- 初めまして。フォームから送信した人に、期間限定のリンクを自動生成して送信し、期間内であれば指定したページが見れて、期間外であれば404ページが表示される、というようにする場合はどのようにすれば良いでしょうか? -- [[masa]] &new{2016-12-18 (日) 16:54:04};
- ds --  &new{2017-02-22 (水) 14:59:59};
- ds -- [[ddd]] &new{2017-02-22 (水) 15:00:15};
- ああ --  &new{2018-03-15 (木) 11:05:11};
- ああ --  &new{2018-03-15 (木) 11:05:11};
- ああ -- [[ああ]] &new{2018-03-15 (木) 11:05:14};
- ssssss -- [[ssss]] &new{2019-12-21 (土) 16:33:51};
- ssssss -- [[ssss]] &new{2019-12-21 (土) 16:33:53};
- ssssss -- [[ssss]] &new{2019-12-21 (土) 16:33:54};
- ssssss -- [[ssss]] &new{2019-12-21 (土) 16:33:58};
- ssssss -- [[ssss]] &new{2019-12-21 (土) 16:33:58};
- a -- [[a]] &new{2020-06-15 (月) 10:27:38};

#comment
#topicpath


SIZE(10){現在のアクセス:&counter;}

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS