.NET TIPS

[ASP.NET]ページ単位にユーザーのアクセス可否を制御するには?

山田 祥寛
2004/07/02

 別稿「TIPS:[ASP.NET]構成ファイルの適用範囲を限定するには?」では、ファイルごとに異なるアクセス制限を設定する方法を紹介した。しかし、web.configの設定をご覧になれば容易に想像できるように、<location>要素の記述は極めて煩雑で、時として構成ファイルの保守性を劣化させる原因となる。

 そのため、もしページ単位またはユーザー単位にアクセスの可否を綿密に制御したいという場合には、データベース・サーバで権限情報を管理する方がより好ましい。本稿では、ユーザーの権限とページ・アクセスに必要な権限をデータベースに格納しておき、ページがアクセスされたときにそれらを比較することによりアクセスを制御する方法を紹介する。

 なお、データベース・サーバを用いたユーザー管理については、別稿「TIPS:[ASP.NET]フォーム認証のユーザー管理をデータベース・サーバで行うには?」で紹介しているので、こちらも併せて参照していただきたい。本稿では、その設定(データベースによるフォーム認証のユーザー管理)がすでになされていることを前提に、追加部分の機能についてのみ紹介する。

1. アクセス管理用のテーブルを定義する

 本稿のサンプル・コード(後述)を動作させるには、データベース上に、あらかじめ以下のようなアクセス管理用の「authテーブル」を定義しておく必要がある。

フィールド名 データ型 概要
url VARCHAR(100) ページのURL(主キー)
role VARCHAR(100) ページが要求する権限(複数ある場合には、カンマ区切り)
authテーブルのフィールド・レイアウト
本稿のサンプル・コード(後述)を動作させるには、データベース上に、あらかじめアクセス管理用の「authテーブル」を定義しておく必要がある。

 authテーブルには仮に以下のようなデータが含まれているものとする。urlフィールドには、仮想ディレクトリ上での絶対パスの形式で指定する。

urlフィールド roleフィールド
/netIns/auth/db_read_cs.aspx admin,super
/netIns/auth/db_read_vb.aspx usr
authテーブルのサンプル・データ

2. アクセス・チェックの方法を定義する

 アクセス・チェックの仕組みは、認証が完了したタイミングで発生するGlobal.asaxのApplication_OnAuthorizeRequestイベント・ハンドラに実装する。(当然ではあるが)Application_OnAuthorizeRequest以前に呼び出されるイベント・ハンドラからは認証済みユーザーに関する情報にはアクセスできないので、注意すること。

 Global.asaxに関する詳細は、別稿「TIPS:[ASP.NET]アプリケーション共通のロギングを行うには?(Global.asax編)」で紹介しているので、併せて参照するとよいだろう。

<%@ Application Description="Insider.NET Sample" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<script Language="C#" runat="Server">
void Application_OnAuthorizeRequest(Object sender, EventArgs e){
  // アクセスの可否を判定するためのフラグ(初期値は「不可」)
  Boolean flag=false;

  SqlConnection objDb=new SqlConnection("Data Source=(local);User ID=sa;Password=sa;Persist Security Info=True;Initial Catalog=dotnet");
  objDb.Open();
  SqlCommand objCom1 = new SqlCommand("SELECT role FROM auth WHERE url=@url", objDb);
  objCom1.Parameters.Add("@url",Request.CurrentExecutionFilePath);
  SqlDataReader objDr1 = objCom1.ExecuteReader();

  // カレント・ページのURLをキーにauthテーブルを検索
  // 権限の設定情報が存在する場合にのみ以下の処理を継続する
  if (objDr1.Read()) {
    // ページへのアクセスに必要な権限情報を文字列配列pageRoleに格納
    String[] pageRole = objDr1.GetString(0).Split(",".ToCharArray());
    objDr1.Close();
    SqlCommand objCom2 = new SqlCommand("SELECT role FROM usr WHERE uid=@uid", objDb);
    objCom2.Parameters.Add("@uid",User.Identity.Name);
    SqlDataReader objDr2 = objCom2.ExecuteReader();

    // 認証済みユーザーの権限とページが要求する権限とを比較する
    // ユーザー権限が1つでもページ権限に合致した場合には
   
// フラグをtrueに設定
    if (objDr2.Read()) {
      String[] role = objDr2.GetString(0).Split(",".ToCharArray());
      for (int i = 0; i < role.GetUpperBound(0); i++){
        if (Array.IndexOf(pageRole, role[i])>-1) { flag = true; }
      }
    }
    // フラグがfalseの場合、カレント・ユーザーでのアクセスは
    // 認められないものと見なして、
   
// エラー・ステータス「403 Forbidden」を発行
    if(!flag){
      Response.Clear();
      Response.StatusCode = 403;
      Response.End();
    }
  }
  objDb.Close();
}
</script>
認証済みユーザーのアクセス・チェックを行うGlobal.asax(C#版)
 
<%@ Application Description="Insider.NET Sample" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<script Language="VB" runat="Server">
Sub Application_OnAuthorizeRequest(sender As Object, e As EventArgs)
  ' アクセスの可否を判定するためのフラグ(初期値は「不可」)
  Dim flag As Boolean =False

  Dim objDb As New SqlConnection("Data Source=(local);User ID=sa;Password=sa;Persist Security Info=True;Initial Catalog=dotnet")
  objDb.Open()
  Dim objCom1 As New SqlCommand("SELECT role FROM auth WHERE url=@url",objDb)
  objCom1.Parameters.Add("@url",Request.CurrentExecutionFilePath)
  Dim objDr1 As SqlDataReader=objCom1.ExecuteReader()

  ' カレント・ページのURLをキーにauthテーブルを検索
  ' 権限の設定情報が存在する場合にのみ以下の処理を継続する
  If objDr1.Read() Then
    ' ページへのアクセスに必要な権限情報を文字列配列pageRoleに格納
    Dim pageRole As String()=objDr1.GetString(0).Split(",")
    objDr1.Close()
    Dim objCom2 As New SqlCommand("SELECT role FROM usr WHERE uid=@uid",objDb)
    objCom2.Parameters.Add("@uid",User.Identity.Name)
    Dim objDr2 As SqlDataReader=objCom2.ExecuteReader()

    ' 認証済みユーザーの権限とページが要求する権限とを比較する
    ' ユーザー権限が1つでもページ権限に合致した場合には
   
' フラグをTrueに設定
    If objDr2.Read() Then
      Dim role As String()=objDr2.GetString(0).Split(",")
      For i As Integer=0 To role.GetUpperBound(0)
        If Array.IndexOf(pageRole,role(i))>-1 Then flag=True
      Next
    End If
    ' フラグがFalseの場合、カレント・ユーザーでのアクセスは
    ' 認められないものと見なして、
   
' エラー・ステータス「403 Forbidden」を発行
    If Not flag Then
      Response.Clear()
      Response.StatusCode=403
      Response.End()
    End If
  End If
  objDb.Close()
End Sub
認証済みユーザーのアクセス・チェックを行うGlobal.asax(VB.NET版)

 ここで行っているアクセス・チェックの仕組みそのものは、ごく単純だ。カレント・ユーザー名をキーにusrテーブルから取得した権限情報(roleフィールド)を、authテーブルに含まれる該当URLの権限情報と比較すればよい。もしもauthテーブルにカレント・ページの情報が存在しない場合には、認証済みの全ユーザーがアクセス可能であると見なすこととする。

 カレント・ユーザーの権限が、ページが要求する権限を満たしていれば、そのままリクエスト処理を継続するが、もしもカレント・ユーザーの権限がページ権限に合致しない場合には、HttpResponse.StatusCodeプロパティで403(Forbidden)をセットする。これによって、権限を持たないユーザーに対しては、以下のようなエラー・ページが表示されるようになる。

権限を持たないユーザーがページにアクセスした場合のエラー・ページの表示

 このエラー・ページにより、アクセス禁止の旨をユーザーに通知することができる。End of Article

カテゴリ:Webフォーム 処理対象:認証
関連TIPS:[ASP.NET]構成ファイルの適用範囲を限定するには?
関連TIPS:[ASP.NET]フォーム認証のユーザー管理をデータベース・サーバで行うには?
関連TIPS:[ASP.NET]アプリケーション共通のロギングを行うには?(Global.asax編)
 
この記事と関連性の高い別の.NET TIPS
[ASP.NET]フォーム認証のユーザー管理をデータベース・サーバで行うには?
[ASP.NET]認証後のページでカスタムのユーザー情報を引用するには?
[ASP.NET]フォーム認証のユーザー管理をXMLファイルで行うには?
[ASP.NET]構成ファイルの適用範囲を限定するには?
[ASP.NET]構成ファイルのみでフォーム認証を実現するには?
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

「.NET TIPS」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間