« 液晶割れ | トップページ | ログイン失敗時のメッセージを増やしたい on Spring Boot »

2017年9月10日 (日)

ログイン/ログアウト前後でクエリパラメータを保つ on Spring Boot

0. ことのはじまり

僕は現在、都合により外に出されているんだけど、先日22:00くらいに自宅で自社のグループウェアを開いてみると、弊社内にいる後輩君から「助けてくださ~い(´;ω;`)」とかいうメールが。

いわく、「Spring Bootを使っているアプリがあり、認証にSpring Securityを使っているが、ログイン/ログアウトの際にクエリパラメータ(※ページのアドレスの後ろについている「?」以降のアレ)を保つ必要があり、どうやったらいいのか自分ではわからない」とのことらしい。

まぁ、自分で調べる際の検索キーワードの選定がまずいだけ、のような気もしないでもないのだが、とりあえず参照実装作成までを目標にして、どうやったらいいかを調べてみた。

ということなので、どういう想定でいくかの整理をしてみる。

  • Spring Bootの最新安定版(現時点では1.5.6.RELEASE)を使用
  • 依存ライブラリは、Thymeleaf、Spring Securityと、JS処理用にjQuery 2.1.4を追加
  • 認証には、データアクセスではなくインメモリ認証を使う
  • クエリパラメータはpだけを認識する

というわけなので、やってみる。

1. やること

いろいろググってみたところ、やらなければならないことは以下の3つだということが判明。

  1. 認証ハンドラを実装したクラスを用意し、その中でクエリパラメータを右から左にリレーする処理を書く。
  2. WebSecurityConfigurerAdapter の継承クラスで、1.で作成した認証ハンドラを使う設定を書く。
  3. Viewからのアクセスは、単純なsubmitやaタグのhrefで処理するのではなく、JSでaction属性やhref属性を直接操作する。

2. 実際には

2-1. カスタム認証ハンドラの実装

必要なカスタム認証ハンドラは、以下のとおり。

処理されるタイミング 実装するinterface
ログイン成功時 org.springframework.security.web.authentication.AuthenticationSuccessHandler
ログイン失敗時 org.springframework.security.web.authentication.AuthenticationFailureHandler
ログアウト時 org.springframework.security.web.authentication.logout.LogoutHandler

とりあえずログイン成功時だけ乗せるけど、HttpSevletRequestからクエリパラメータの文字列をとって、リダイレクトURLにぶら下げなおす、というのが基本。

public class AuthSuccess implements AuthenticationSuccessHandler {

  @Override
  public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
      Authentication authentication) throws IOException, ServletException {
    
    // add whole query parameters to url 
    String queryParams = request.getQueryString() == null ? "" : "?" + request.getQueryString();

    RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
    redirectStrategy.sendRedirect(request, response, "/menu" + queryParams );
  }

}

2-2. WebSecurityConfigurerAdapterに認証ハンドラをセット

Spring Securityを入れていると、その構成を行うJavaConfigがあるはずだが、そこをこんな感じに書き換える。

http.formLogin()
    .loginProcessingUrl("/login")
    .loginPage("/login")
    .successHandler(new AuthSuccess())  // ログイン成功時のカスタムハンドラ
    .failureHandler(new AuthFailure())  // ログイン失敗時のカスタムハンドラ
    .permitAll();

http.logout()
    .logoutRequestMatcher(new AntPathRequestMatcher("/logout**"))
    .addLogoutHandler(new LogoutPostProcess())  // ログアウト時のカスタムハンドラ
    .deleteCookies("JSESSIONID")
    .invalidateHttpSession(true);

それぞれカスタム認証ハンドラを設定するためのメソッドが用意されているので、そこにオブジェクトを放り込めばOK。

2-3. JSでURLをたたく

フロント系中心にやってる人にはどうということはないんだけど、通常 <input type="submit"> とか <a href="hogehoge"> とかで書いている処理を、JavaScriptでクエリパラメータを取得してURLをたたくようにすればOK。

/**
 * URLについているクエリパラメータを取得して、Formのaction属性を書き換えてsubmitする処理。
 */
function sendReq() {
  var arg = getQueryParam();
  
  var url = $('#loginForm').attr('action');
  if (arg.p != null) {
    url += '?p=' + arg.p;
  }

  $('#loginForm').attr('action', url);
  $('#loginForm').submit();
}

/**
 * URLについているクエリパラメータを取得する処理。
 */
function getQueryParam() {
  var arg = new Object;
  var pair = location.search.substring(1).split('&');
  for (var i = 0; pair[i]; i++) {
    var kv = pair[i].split('=');
    arg[kv[0]] = kv[1];
  }
  
  return arg;
}

/**
 * URLについているクエリパラメータを取得して特定ページへ遷移する処理。
 */
function doLogout() {
  var proto = location.protocol;
  var host = location.host;

  var url = proto + '//' + host + '/logout';
  
  var arg = getQueryParam();
  if (arg.p != null) {
    url += '?p=' + arg.p;
  }
  
  location.href = url;
}

3. とりあえず動かせる参照実装

GitHubに上げました。ご参照あれ。
f97one/AddingQueryParamsDemo

|

« 液晶割れ | トップページ | ログイン失敗時のメッセージを増やしたい on Spring Boot »

コメント

コメントを書く



(ウェブ上には掲載しません)




トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/164672/65774184

この記事へのトラックバック一覧です: ログイン/ログアウト前後でクエリパラメータを保つ on Spring Boot:

« 液晶割れ | トップページ | ログイン失敗時のメッセージを増やしたい on Spring Boot »