// 下階層用テンプレート #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(おもしろかった[227],そうでもない[31]) - その他のリンク系のタグは、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}; #comment #topicpath SIZE(10){現在のアクセス:&counter;}