struts 2におけるtokenのトークンメカニズム
9748 ワード
通常、通常の操作では、重複コミットを処理する必要はなく、重複コミットを防止する方法がたくさんあります.たとえば、ログイン中にredirectを使用すると、ユーザーがログインしてバックグラウンドのトップページインタフェースにリダイレクトすることができ、ユーザーがインタフェースをリフレッシュすると、重複コミットはトリガーされません.またはtokenを使用してフォームに非表示にし、コミット時にtoken検証を行い、検証に失敗してもコミットを許可しません.これはすべて一般的なやり方です.
私たちが今回直面した問題は、重複コミット自体がエラーであり、重複コミットは関連データの論理が正しくないことです.これらの繰返しコミットは,通常のインタフェースのリフレッシュやボタンの2回のクリックで行われるものではない.通常の操作では,対応するパラメータをクリアし,データ上の不正を防止する一連の手段を用いることができる.しかし、1つの場合、これらの手段は有効ではありません.それは、同時提出です. 同時反復コミットは、同じ時間内(時間間隔を0.X秒以内に短縮できる)であり、この場合、複数のリクエストが同時にシステムに入るため、システムはこれらのリクエストが無効であるかどうかを判断することができず、通常の反復ロジックによって判断されるため、すべての従来のロジックは有効ではありません.最終的に同じ時間にデータベースにデータを書き込み、データエラーを引き起こします.
簡単な例を挙げると、システムで1つの商品を販売するには、まず、その商品idがシステムロジックに入ることによって、その商品が販売されたか否かを判断し、販売されていない場合は、データアクセス操作を行う.商品が販売されているかどうかは、データがデータベースに格納されていることを検証する論理的な判断です.通常の判断では、前の要求がこのドアを通過した後、後の要求はfalseとして検証されたため通過できません.しかしコンカレントリクエストでは,2つ以上のリクエストが同時にこのゲートを通過し,いずれも同時に判定に入り,判定前に商品が販売されていないことを検証したため,同時にデータの格納に入った.
従来のjava開発では、この場合、臨界リソースは、通常、このような状況の前後順序を保証するためにロックを使用する.しかし、ロックには、グローバル情報のロック、すなわち販売される商品全体にロックがかかっているという問題がある.BSアプリケーションでは、別のオペレータの同じ商品の販売要求が通過することを保証しなければならない.すなわち、同じオペレータの販売のみを制限する同時要求であり、複数のオペレータの異なる要求の処理を制限しない. この場合、私たちのロックは簡単に商品にロックするのではなく、操作者に関する情報にロックします.これがsessionです.
sessionは、単一のオペレータが操作中にサーバ側と通信を維持する唯一の識別情報である.同じオペレータの複数回のリクエストでは、sessionは常に複数のオブジェクトではなく、同じオブジェクトであることを保証します.なぜなら、sessionはロックをかけることができるからです.同じオペレータが複数のリクエストにアクセスする場合、セッション制限により一方向通行のみが可能になります. 本明細書では、セッションを使用してtokenをセッションに追加することによって、同じオペレータが同時反復要求を行ったかどうかを検証し、後の要求が来た場合、セッション内のtokenを使用して要求中のtokenが一致しているかどうかを検証し、一致しない場合、反復送信とみなされ、通過を許可しない.
原理:サーバ側はクライアントの要求を処理する前に、要求に含まれるトークン値を現在のセッションに保存されているトークン値と比較し、一致するかどうかを確認します.要求を処理した後、情報がクライアントに達する前に、新しいトークンが生成される.トークン値は、現在のセッションのトークン値を置き換え、クライアントに渡されます.これにより,ユーザがさっきのコミットページにロールバックして再度コミットすると,クライアントから送信されたトークンがサービス内のトークン値と一致せず,コミットが有効に防止される.実装:まず、事前に追加されたActionのexecute()メソッドでトークンsaveToken(request)を作成して保存します.機能:新しいトークン値を作成し、現在のセッションに保存します.HttpSessionオブジェクトが存在しない場合は、まずこのオブジェクトを作成します.追加されたアクションによってトークンが追加されたページに転送され、非表示ドメインとして使用されます.追加ページが追加AddActionにコミットされた後、execute()メソッドでは、現在のセッションのトークン値とリクエストのトークン値が一致しているかどうかを判断します.isTokenValid(request)が一致していない場合は、エラーメッセージが表示され、saveToken(request)を介して、トークン値をリフレッシュします.一致する場合は、sql文の保存(追加)を実行し、resetToken(request)メソッドで現在のセッションのトークンを削除します. プロセス全体は次のように記述できます.
クライアント申請token サーバ側はtokenを生成し、セッションに格納し、クライアントにtokenを送信する.
クライアントはtokenを格納し、要求送信時にtoken情報を同時に送信する.
サーバ側は、同じユーザのすべての要求を統一的にブロックし、現在の要求が検証される必要があるかどうかを検証する(すべての要求が重複送信を検証するわけではない).
セッション内のtokenがユーザーリクエストのtokenと一致しているかどうかを確認し、一致している場合はを実行します.
セッションはセッション内のtokenをクリアし、次のtoken生成の準備を行う.
同時反復要求が到来し、tokenと要求tokenが一致しないことを検証し、要求は拒否された.
以上のプロセスによって、私たちが実現するには以下のいくつかのものが必要です.
tokenジェネレータ、token の生成を担当
顧客token要求処理actionは、顧客要求の処理を担当し、token情報に戻る.
指定されたリクエストをブロックするためにtoken を検証する必要があるかどうか
token要求ブロック識別は、どの要求がブロックする必要があるかを識別するためのである.
クライアントtoken要求処理方法は、tokenを要求し、特定の操作に格納し、コミット時に要求中に送信する.
tokenジェネレータ tokenジェネレータは、以下に示すように、ランダムに数値を生成するランダム数、すなわちtoken生成を実現するためにここで使用される.
token要求処理action 要求処理actionは、対応する要求を受信し、対応するtokenに直接戻ることであり、ajax要求のためにtokenを生成する処理actionである.
token要求ブロックID ブロックIDは、どのメソッドがブロックされる必要があるかを示すものであり、ブロックするメソッドに@TokenNeedのような注釈を追加するか、またはプロファイルを使用してブロックする必要があるメソッドのリストをプロファイルに記録するか、ここではプロファイルを1つで記録させる
tokenブロッキング tokenブロッキングは、ブロッキングが必要なメソッド要求に遭遇した場合、tokenの判断と処理を同期して行い、処理結果に基づいて、ブロッキングを継続するか、ブロックするかを判断するために必要なブロッキング処理を実現します.
以上のように処理方法がブロックリストにあるか否かを判断し、もしそうであればパラメータ中のtokenを取得し、session中のtokenと比較して一致しなければ直接failに戻り、その後sessionから除去する.
クライアントtoken実装 クライアントとしては、リクエストの送信前にtokenを申請し、リクエスト時にこのtokenをリクエストに追加するだけです.本明細書では、jqueryのajaxメソッドがtokenリクエストを処理し、ajaxリクエストを行うときにこのtokenをparamに一緒に追加する.以下、tokenのjqueryリクエスト
すなわち、処理時に受信したtokenをwindowに入れ、要求を提出するときにwindowから取り出し、一括して提出すればよい.以下の統一ajax処理方法である.
これで、セッション防止Tokenリクエスト全体が完了します.クライアントが複数のリクエストをシミュレートする場合、最初に1つのリクエストが正常に処理され、他のリクエストはajaxリクエストの場合、「繰り返しコミットできません」のようなエラー警告を直接返します.
私たちが今回直面した問題は、重複コミット自体がエラーであり、重複コミットは関連データの論理が正しくないことです.これらの繰返しコミットは,通常のインタフェースのリフレッシュやボタンの2回のクリックで行われるものではない.通常の操作では,対応するパラメータをクリアし,データ上の不正を防止する一連の手段を用いることができる.しかし、1つの場合、これらの手段は有効ではありません.それは、同時提出です. 同時反復コミットは、同じ時間内(時間間隔を0.X秒以内に短縮できる)であり、この場合、複数のリクエストが同時にシステムに入るため、システムはこれらのリクエストが無効であるかどうかを判断することができず、通常の反復ロジックによって判断されるため、すべての従来のロジックは有効ではありません.最終的に同じ時間にデータベースにデータを書き込み、データエラーを引き起こします.
簡単な例を挙げると、システムで1つの商品を販売するには、まず、その商品idがシステムロジックに入ることによって、その商品が販売されたか否かを判断し、販売されていない場合は、データアクセス操作を行う.商品が販売されているかどうかは、データがデータベースに格納されていることを検証する論理的な判断です.通常の判断では、前の要求がこのドアを通過した後、後の要求はfalseとして検証されたため通過できません.しかしコンカレントリクエストでは,2つ以上のリクエストが同時にこのゲートを通過し,いずれも同時に判定に入り,判定前に商品が販売されていないことを検証したため,同時にデータの格納に入った.
従来のjava開発では、この場合、臨界リソースは、通常、このような状況の前後順序を保証するためにロックを使用する.しかし、ロックには、グローバル情報のロック、すなわち販売される商品全体にロックがかかっているという問題がある.BSアプリケーションでは、別のオペレータの同じ商品の販売要求が通過することを保証しなければならない.すなわち、同じオペレータの販売のみを制限する同時要求であり、複数のオペレータの異なる要求の処理を制限しない. この場合、私たちのロックは簡単に商品にロックするのではなく、操作者に関する情報にロックします.これがsessionです.
sessionは、単一のオペレータが操作中にサーバ側と通信を維持する唯一の識別情報である.同じオペレータの複数回のリクエストでは、sessionは常に複数のオブジェクトではなく、同じオブジェクトであることを保証します.なぜなら、sessionはロックをかけることができるからです.同じオペレータが複数のリクエストにアクセスする場合、セッション制限により一方向通行のみが可能になります. 本明細書では、セッションを使用してtokenをセッションに追加することによって、同じオペレータが同時反復要求を行ったかどうかを検証し、後の要求が来た場合、セッション内のtokenを使用して要求中のtokenが一致しているかどうかを検証し、一致しない場合、反復送信とみなされ、通過を許可しない.
原理:サーバ側はクライアントの要求を処理する前に、要求に含まれるトークン値を現在のセッションに保存されているトークン値と比較し、一致するかどうかを確認します.要求を処理した後、情報がクライアントに達する前に、新しいトークンが生成される.トークン値は、現在のセッションのトークン値を置き換え、クライアントに渡されます.これにより,ユーザがさっきのコミットページにロールバックして再度コミットすると,クライアントから送信されたトークンがサービス内のトークン値と一致せず,コミットが有効に防止される.実装:まず、事前に追加されたActionのexecute()メソッドでトークンsaveToken(request)を作成して保存します.機能:新しいトークン値を作成し、現在のセッションに保存します.HttpSessionオブジェクトが存在しない場合は、まずこのオブジェクトを作成します.追加されたアクションによってトークンが追加されたページに転送され、非表示ドメインとして使用されます.追加ページが追加AddActionにコミットされた後、execute()メソッドでは、現在のセッションのトークン値とリクエストのトークン値が一致しているかどうかを判断します.isTokenValid(request)が一致していない場合は、エラーメッセージが表示され、saveToken(request)を介して、トークン値をリフレッシュします.一致する場合は、sql文の保存(追加)を実行し、resetToken(request)メソッドで現在のセッションのトークンを削除します. プロセス全体は次のように記述できます.
クライアント申請token サーバ側はtokenを生成し、セッションに格納し、クライアントにtokenを送信する.
クライアントはtokenを格納し、要求送信時にtoken情報を同時に送信する.
サーバ側は、同じユーザのすべての要求を統一的にブロックし、現在の要求が検証される必要があるかどうかを検証する(すべての要求が重複送信を検証するわけではない).
セッション内のtokenがユーザーリクエストのtokenと一致しているかどうかを確認し、一致している場合はを実行します.
セッションはセッション内のtokenをクリアし、次のtoken生成の準備を行う.
同時反復要求が到来し、tokenと要求tokenが一致しないことを検証し、要求は拒否された.
以上のプロセスによって、私たちが実現するには以下のいくつかのものが必要です.
tokenジェネレータ、token の生成を担当
顧客token要求処理actionは、顧客要求の処理を担当し、token情報に戻る.
指定されたリクエストをブロックするためにtoken を検証する必要があるかどうか
token要求ブロック識別は、どの要求がブロックする必要があるかを識別するためのである.
クライアントtoken要求処理方法は、tokenを要求し、特定の操作に格納し、コミット時に要求中に送信する.
tokenジェネレータ tokenジェネレータは、以下に示すように、ランダムに数値を生成するランダム数、すなわちtoken生成を実現するためにここで使用される.
1 private static final Random random = new Random(System.currentTimeMillis()); 2 public static final String TOKENPARAM = "session-token"; 3
4 /** token */
5 public static synchronized String generateToken(HttpSession session) { 6 String s = String.valueOf(random.nextLong()); 7 session.setAttribute(TOKENPARAM, s); 8 return s; 9 }
token要求処理action 要求処理actionは、対応する要求を受信し、対応するtokenに直接戻ることであり、ajax要求のためにtokenを生成する処理actionである.
1 public String generateTokenAjax() { 2 String token = SessionTokenGenerator.generateToken(ServletActionContext.getRequest().getSession()); 3 AjaxSupport.sendSuccessText(token); 4 return NONE; 5 }
token要求ブロックID ブロックIDは、どのメソッドがブロックされる必要があるかを示すものであり、ブロックするメソッドに@TokenNeedのような注釈を追加するか、またはプロファイルを使用してブロックする必要があるメソッドのリストをプロファイルに記録するか、ここではプロファイルを1つで記録させる
tokenブロッキング tokenブロッキングは、ブロッキングが必要なメソッド要求に遭遇した場合、tokenの判断と処理を同期して行い、処理結果に基づいて、ブロッキングを継続するか、ブロックするかを判断するために必要なブロッキング処理を実現します.
1 public String intercept(ActionInvocation invocation) throws Exception { 2 String action = invocation.getProxy().getAction().getClass().getName(); 3 String method = invocation.getProxy().getMethod(); 4 final HttpSession session = ServletActionContext.getRequest().getSession(); 5 if(includeMethodSet.contains(action + "." + method)) { 6 synchronized(session) { 7 String paramSessionToken = ServletActionContext.getRequest().getParameter(SessionTokenGenerator.TOKENPARAM); 8 String sessionSessionToken = (String) session.getAttribute(SessionTokenGenerator.TOKENPARAM); 9 if(sessionSessionToken == null || paramSessionToken == null || !paramSessionToken.equals(sessionSessionToken)) 10 return fail(); 11 session.removeAttribute(SessionTokenGenerator.TOKENPARAM); 12 } 13 } 14 return invocation.invoke(); 15 }
以上のように処理方法がブロックリストにあるか否かを判断し、もしそうであればパラメータ中のtokenを取得し、session中のtokenと比較して一致しなければ直接failに戻り、その後sessionから除去する.
クライアントtoken実装 クライアントとしては、リクエストの送信前にtokenを申請し、リクエスト時にこのtokenをリクエストに追加するだけです.本明細書では、jqueryのajaxメソッドがtokenリクエストを処理し、ajaxリクエストを行うときにこのtokenをparamに一緒に追加する.以下、tokenのjqueryリクエスト
1 m_ylf.token = function() { 2 m_ylf.invoke("/token/generateToken",{}, function(re) { 3 re = re["result"]; 4 window["session-token"] = re; 5 }); 6 }
すなわち、処理時に受信したtokenをwindowに入れ、要求を提出するときにwindowから取り出し、一括して提出すればよい.以下の統一ajax処理方法である.
1 // session-token
2 if(window["session-token"]) 3 param["session-token"] = window["session-token"];
これで、セッション防止Tokenリクエスト全体が完了します.クライアントが複数のリクエストをシミュレートする場合、最初に1つのリクエストが正常に処理され、他のリクエストはajaxリクエストの場合、「繰り返しコミットできません」のようなエラー警告を直接返します.