私は、それぞれがホーム、トピック、postedit、ログイン、およびユーザーリストのページを表す一連のServlets
を使用した単純なフォーラムを行っています。これらのページの一部には、ユーザーがログインしていないときに表示されるリンクがあります。
私が達成したいのは、ログイン後にリダイレクトをトリガーして(RequestDispatcherでforward()を使用)、ブラウザーがログインリンクをクリックする前にユーザーがいたページに戻るようにすることです。これを行うために、2つの解決策があります。
最初の解決策は、ログインボタンとForm
としてリダイレクトするページを示す情報を含む非表示フィールドを備えたHTMLParameter
を用意することです。これは実行可能ですが、別のことを試してみたいと思います。
2番目の解決策は、何らかの方法で最初の「ページ」を表すAttribute
にsession
を追加することです。これには文字列を含めることができますが、これは最初のアプローチと同じです。もう1つの工夫は、HttpServletへの参照を追加し、instanceofまたは何らかの方法でサーブレットを識別するために使用できる静的文字列変数を使用することです。ただし、これには、すべてのServlets
に共通の祖先クラスを作成する必要があります。
おそらく、良い妥協点を形成することがわかる別の簡単な解決策がありますか?または、上記の解決策の1つが完全に受け入れられるのでしょうか?
私は2番目の解決策よりも最初の解決策を好みます。これはrequestスコープ情報であり、実際にはセッションに属していません。「wtf?」につながるだけです。同じセッションで複数のウィンドウ/タブを開いている場合のエクスペリエンス。
ログインページへのリンクで、現在のURLをリクエストパラメータとして渡すだけです。
_<a href="/login?from=${pageContext.request.requestURI}">Login</a>
_
または、ログインページへのPOSTフォームの場合:
_<input type="hidden" name="from" value="${pageContext.request.requestURI}">
_
ログインフォームで、それを隠れた変数として次のリクエストに転送します。
_<input type="hidden" name="from" value="${param.from}">
_
ログインサーブレットで、それを利用します。
_User user = userDAO.find(username, password);
if (user != null) {
request.getSession().setAttribute("user", user);
response.sendRedirect(request.getParameter("from"));
} else {
// Show error.
}
_
かなり簡単ですね。 :)
ログイン前のリンク/ボタンのrequest.getHeader("referer")
の代わりにログインフォーム内でこれにrequest.getRequestURI()
を使用することを提案する人もいるかもしれませんが、これはクライアント制御であり、常に信頼できる情報を返すとは限りません。一部のクライアントは、それを無効にしている、またはほとんどの(cough)Symantec製品のように、無効な値でスプーフィングするソフトウェアを使用しています。
最初に提案されたアプローチが最良のアプローチです。 value=request.getRequestURI()
を含む非表示フィールドを用意し、ログイン後にそのURIにリダイレクトします。
IE(少なくともそのバージョンの一部)はreferer
ヘッダーを設定しないため、referer
の使用は機能しません。
ユーザーが複数のタブを開いた場合、セッションにパラメータを保存すると、奇妙な動作が発生します。
編集:質問をよりよく説明するために:
some resource -> (requests protected resource) -> (gets forwarded to the login page) -> (should be redirected to the original resource)
ほとんどの回答は、「ログイン」リンク/ボタンがクリックされた後、ログインページが開かれることを前提としています。これは話の片側にすぎません。その場合、元のリソースURLをパラメーターとして追加し、ログインフォーム(非表示フィールド)に配置できます。
ただし、保護されたリソースからログインページへの転送の場合、非表示フィールドには即時リクエストURLが含まれている必要があります。
もちろん、これは問題ではありませんが、最終的には状況として発生するため、同様に考慮する必要があります。
ページでこれを行いたい場合、ログインページはそれをロードしたリクエストのリファラー(sic)ヘッダー(request.getHeader("referer")
)を見て、それがサイトのページであるかどうかを確認できます(そうでない場合は-または、ヘッダーが欠落している場合-何らかのデフォルトを使用します)。次に、そのURLを保存します(あなたが言ったように、ログインフォームではおそらく非表示のフィールドを使用しますが、セッション変数も機能します)。ログインが完了したら、保存されているURLへのリダイレクトを発行します。
最近では、ページにダイアログをオーバーレイしてAjax経由でログインすることでログインできない場合は、フォールバックメカニズムとしてこれらすべてを使用する可能性があります。そのため、ページを離れることはありません。
編集またはさらに良いことに、Bozhoが指摘しているように、ターゲットページをログインページへのリンクにエンコードします。 IEが "referer"ヘッダーを設定しない(設定する)ことはnottrueですが、refererは設定されません必須であり、無効にすることができます。また、ログインフォームにリンクするページを既に動的に作成しているので、必要がないのに、なぜ脆弱であるのか。
差出人: http://static.springsource.org/spring-security/site/docs/3.0.x/reference/springsecurity.pdf
章:認証の成功と失敗に関するアプリケーションフロー
...認証が成功すると、結果のAuthenticationオブジェクトがSecurityContextHolderに配置されます。次に、構成されたAuthenticationSuccessHandlerが呼び出され、ユーザーを適切な宛先にリダイレクトまたは転送します。デフォルトでは、SavedRequestAwareAuthenticationSuccessHandlerが使用されます。これは、ユーザーがログインを求められる前に、要求した元の宛先にリダイレクトされることを意味します。 .。
フォームで非表示フィールドを使用することはかなり標準的です。なぜ車輪の再発明を試みるのですか?
わかりました、これが私がしたことです。ログインは2段階のプロセスであり、1つのサーブレットがフォームを表示し、別のサーブレットがユーザー名とパスワードの組み合わせが正しいかどうかを制御します。 2つを組み合わせることができます。
パラメータは、フォームまたはリンクを介して送信できます(JSPはまだ追加されていません)。
out.println( "Login <a href='LoginServlet?comeback=home'>here</a><br>" );
次に、パラメータは次のように取得されます。
String comeback = request.getParameter("comeback");
ログイン情報を確認したら、次のようにリダイレクトを実行できます。
RequestDispatcher rd = request.getRequestDispatcher( redirectionPath );
if( rd != null )
rd.forward(request, response);