サーブレットのアクセス認可機能
サーブレット仕様では認証・認可機能が定義されており、サーブレットコンテナはroleによるアクセス制御機能をサポートしている。
roleによるアクセス制御は HttpServletRequest#isUserInRole(String) を利用している。Strutsのlogic:presentタグのrole属性や、アクションのrole属性もこれを利用している。
サーブレット仕様の認証を使わずにgetRemoteUserやisUserInRoleを使う。
ロールによるアクセス制御を使うにはサーブレットコンテナの認証機能を使わなくてはならない。認証機能を独自で実装すると、HttpServletRequest#isUserInRole(String) は有効にならない。
しかし、独自の認証でもHttpServletRequestWrapperとFilterを組み合わせれば、getRemoteUserやisUserInRoleを有効にできる。
HttpServletRequestWrapper は HttpServletRequestの機能を簡単に拡張できるようにしたラッパークラスで、デフォルト実装では、内部で持っている HttpServletRequest へ全ての処理を委譲する。
HttpServletRequestの機能を拡張するには、HttpServletRequestWrapperのサブクラスを作り、機能拡張したいAPIだけをオーバーライドすればいい。
まず、認証成功時にユーザ名とロールを適当な名前でセッションに格納する。
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クラスとなり、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を修正する。