2010年7月7日水曜日

slim3使用時のgoogle認証の使い方ではまったところ

slim3使用時のgoogle認証の使い方のハマリどころ。

例えば
http://アプリケーションID/private/
というURLにアクセスした場合に、private下にはすべてgoogle認証をかけたい場合、
以下のようなFilterを作成します。

/**
 * google認証を行うFilterクラス
 */
public class MemberFilter implements Filter {

  @Override
  public void doFilter(ServletRequest request, ServletResponse response,
             FilterChain filterChain) throws IOException, ServletException {

    final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
    final UserService userService = UserServiceFactory.getUserService();

    // リクエストのあったURL
    final String requestUri = httpServletRequest.getRequestURI();

    // googleアカウントにログインしているかを判定するUtilクラス(後述)
    if (AccountUtils.isGoogleLogin(httpServletRequest) == false) {
      ((HttpServletResponse) response).sendRedirect(userService.createLoginURL(requestUri));
      return;
    }

    // ログイン成功
    filterChain.doFilter(request, response);

  }

  @Override
  public void destroy() {
  }

  @Override
  public void init(FilterConfig arg0) throws ServletException {
  }
}

/**
 * google認証を判定するUtilクラス
 */
public class AccountUtils {

  /**
   * googleアカウントにログインしているかを判定する。
   *
   * @param request
   * @return ログインしていればtrue, していなければfalse
   */
  public static boolean isGoogleLogin(final HttpServletRequest request) {

    final UserService userService = UserServiceFactory.getUserService();
    final Principal principal = request.getUserPrincipal();

    if (principal == null || userService.isUserLoggedIn() == false) {
      return false;
    }

    return true;
  }
}


以上です。
この例だと、「/private/」にアクセスした場合に、MembeerFilterクラスのdoFilterが呼ばれ、
17行目のif文でgoogleアカウントにログインしているかをチェックし、
falseならばログインページにリダイレクトされます。

ここで、注目して欲しいのが、14行目のrequestUri。
これがログイン後にリダイレクトされるパスを示しています。
18行目のuserService.createLoginURL(requestUri)では、ログインページのパスを作成し、
このパスには、ログイン後にアクセスするURL、つまり今回の例でいう「/private/」が含まれています。
ただ、ここでハマリどころなのですが、実際にアクセスしようとしたURLが「/private/」となっていても、
14行目で取得できるurlは「/private/index.jsp」
つまり、ログイン後に飛ばされパスは「/private/index.jsp」となってしまいます。
Slim3では、jspファイルに直接アクセスできないようになっているので、
もちろんこれは403エラーになってしまいます。

これを解決するためには、MemberFilterクラスの18行目を、
((HttpServletResponse) response).sendRedirect(userService.createLoginURL(requestUri.replace("index.jsp", "")))

と修正して上げれば、ログイン後に飛ばされるパスから「index.jsp」が削除されるので、
問題なくControllerを経由してページにアクセスできるようになります。