連載
» 2003年11月18日 10時00分 公開

JavaTips 〜JSP/サーブレット編:フィルタでサイト内のアクセス権限を制御する

[山田祥寛,@IT]

 「ユーザ権限でパーソナライズする方法」でもご紹介したように、実際のアプリケーションではカレントユーザーの権限によってアクセスの可否を制御するという機会は少なくありません。しかし、ページが要求する権限とアクセス可否の制御をいちいち個別のページごとに記述していたのではキリがありません。サイト内のアクセス権限をメンテナンスしたいという場合にも、コード本体をいじらなければならず、あまり歓迎すべき状況ではないでしょう。

 ここで用いるのが、「アクセスログ記録のロジックをフィルタで一元化する」でも登場したフィルタのテクニックです。データベースなどでアクセス制御情報を定義しておき、あとは個別のページアクセス時にアクセスの可否を判定します。対象のページやロール権限が増えても、いちいちコード自体を編集、コンパイルする必要がありませんので、柔軟に対応することができます。

 なお、本稿のテクニックでは、以下のテーブルをあらかじめデータベースサーバ上に構築しておく必要があります。

フィールド名 データ型 概要
url VARCHAR(50) アクセス制限対象のURL(主キー)
role VARCHAR(50) アクセスを認めるロール(複数の場合はカンマ区切り)
forbiddenテーブルのレイアウト

解説

 以下のフィルタクラスFilterForbidden.javaを作成し、「/アプリケーションルート/WEB-INF/classes/filter/」フォルダ配下に保存します。また、フィルタクラスの起動条件をデプロイメント・ディスクリプタに記述(追記)してください。

FilterForbidden.java
package filter;
 
import java.io.*;
import java.sql.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
 
public class FilterForbidden implements Filter {
  public void init(FilterConfig objFc){}
  public void destroy(){}
  public void doFilter(ServletRequest request, ServletResponse response, 
FilterChain chain) throws ServletException, IOException {
    try{
      boolean flag=false;
      Class.forName("org.gjt.mm.mysql.Driver");
      Connection db=DriverManager.getConnection("jdbc:mysql://localhost/
atit?user=root&password=root&useUnicode=true&characterEncoding=Shift_JIS");
      PreparedStatement objSql=db.prepareStatement("SELECT * FROM forbidden WHERE url=?");
      objSql.setString(1,((HttpServletRequest)request).getServletPath());
      ResultSet rs=objSql.executeQuery();
      if(rs.next()){
        StringTokenizer objTkn=new StringTokenizer(rs.getString("role"),",");
        while(objTkn.hasMoreTokens()){
          if(((HttpServletRequest)request).isUserInRole(objTkn.nextToken())){
            flag=true;
            break;
          }
        }
      }else{
        flag=true;
      }
      rs.close();
      objSql.close();
      db.close();
      if(!flag){
        ((HttpServletResponse)response).sendError
(HttpServletResponse.SC_FORBIDDEN);
      }
    }catch(Exception e){
      e.printStackTrace();
    }
    chain.doFilter(request,response);
  }
}

 FilterForbiddenクラスでは、カレントユーザーのロールとリクエストされたページが要求するロールとを比較します。その結果、カレントユーザーのロールがページロールを満たしている場合、もしくはリクエストされたページがデータベースに登録されていなかった場合には、そのまま該当ページにアクセスします。リクエストロールが満たされなかった場合にはHTTPステータス「403 Forbidden」を返します。

web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
  <filter>
    <filter-name>FilterForbidden</filter-name>
    <filter-class>filter.FilterForbidden</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>FilterForbidden</filter-name>
    <url-pattern>/auth/*</url-pattern>
  </filter-mapping>
</web-app>

 上記で示しているのはフィルタのマッピングのみですが、実際に使用するに際しては、ユーザー認証のための定義を併記する必要があります。詳細は、「アクセス制限をweb.xmlの記述だけで設定する」を参照してください。

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。