サーブレット仕様の認証を使わずにgetRemoteUserやisUserInRoleを使う。

JavaのWebアプリでユーザ認証を行う場合、サーブレット仕様で決められた認証機能を使うか、独自の認証機構を実装するか、いずれかであると思う。

サーブレットの認証機能を使うとHttpServletRequestのisUserInRoleやgetRemoteUserが有効になるのが地味に嬉しい。Strutsフレームワークのロールによるアクセス制御も有効になるのでサーブレットの認証機能は結構使える。一方、独自の認証機構を使うと自由にログイン処理を記述できる代わりにHttpServletRequestのgetRemoteUserやisUserInRoleは使えない。

しかし独自の認証でもHttpServletRequestWrapperとFilterを組み合わせれば、getRemoteUserやisUserInRoleを有効にできる。

まず、認証時にユーザ名とロールを適当な名前でセッションに格納する。

  session.setAttribute("auth.user", user);
  session.setAttribute("auth.role", role);

HttpServletRequestWrapperを作る。セッションからロールやユーザ名を取り出すようにgetRemoteUserやisUserInRoleをオーバーライドする。

public class AuthHttpServletRequest extends HttpServletRequestWrapper {

    public AuthHttpServletRequest(HttpServletRequest request) {
        super(request);
    }

    public String getRemoteUser(){
        HttpSession session = this.getSession(false);
        if (session == null) {
            return null;
        }
        return (String)session.getAttribute("auth.user");
    }

    public boolean isUserInRole(String str) {
        if (str == null) {
            return false;
        }
        HttpSession session = this.getSession(false);
        if (session == null) {
            return false;
        }

        Object role = session.getAttribute("auth.role");
        return (str.equals(role));
    }
}

フィルタを作る。ここでHttpServletRequestを自作のHttpServletRequestサブクラスでラップして次のフィルタもしくはサーブレットに処理を渡すようにする。このフィルタを噛ませば、サーブレットに渡されるHttpServletRequest実装クラスは自作のHttpServletRequestサブクラスとなり、getRemoteUserやisUserInRoleが有効になるというわけ。

public class AuthFilter implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest  req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        chain.doFilter(new AuthHttpServletRequest((HttpServletRequest)req), res);
    }

    public void init(FilterConfig config) throws ServletException {
    }
}

あとは、web.xmlでこのフィルタをサーブレット全体に適用すれいい。Strutsフレームワークのメソッドのアクセス制御やjspでのlogic:presentによる制御が使えるようになる。もちろんSAStrutsでも有効だ。