2010年7月7日水曜日

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

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

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

  1. /** 
  2.  * google認証を行うFilterクラス 
  3.  */  
  4. public class MemberFilter implements Filter {  
  5.   
  6.   @Override  
  7.   public void doFilter(ServletRequest request, ServletResponse response,  
  8.              FilterChain filterChain) throws IOException, ServletException {  
  9.   
  10.     final HttpServletRequest httpServletRequest = (HttpServletRequest) request;  
  11.     final UserService userService = UserServiceFactory.getUserService();  
  12.   
  13.     // リクエストのあったURL  
  14.     final String requestUri = httpServletRequest.getRequestURI();  
  15.   
  16.     // googleアカウントにログインしているかを判定するUtilクラス(後述)  
  17.     if (AccountUtils.isGoogleLogin(httpServletRequest) == false) {  
  18.       ((HttpServletResponse) response).sendRedirect(userService.createLoginURL(requestUri));  
  19.       return;  
  20.     }  
  21.   
  22.     // ログイン成功  
  23.     filterChain.doFilter(request, response);  
  24.   
  25.   }  
  26.   
  27.   @Override  
  28.   public void destroy() {  
  29.   }  
  30.   
  31.   @Override  
  32.   public void init(FilterConfig arg0) throws ServletException {  
  33.   }  
  34. }  
  35.   
  36. /** 
  37.  * google認証を判定するUtilクラス 
  38.  */  
  39. public class AccountUtils {  
  40.   
  41.   /** 
  42.    * googleアカウントにログインしているかを判定する。 
  43.    * 
  44.    * @param request 
  45.    * @return ログインしていればtrue, していなければfalse 
  46.    */  
  47.   public static boolean isGoogleLogin(final HttpServletRequest request) {  
  48.   
  49.     final UserService userService = UserServiceFactory.getUserService();  
  50.     final Principal principal = request.getUserPrincipal();  
  51.   
  52.     if (principal == null || userService.isUserLoggedIn() == false) {  
  53.       return false;  
  54.     }  
  55.   
  56.     return true;  
  57.   }  
  58. }  

以上です。
この例だと、「/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行目を、
  1. ((HttpServletResponse) response).sendRedirect(userService.createLoginURL(requestUri.replace("index.jsp""")))  

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