C#.NET を使用して ASP.NET アプリケーションにフォーム ベースの認証を実装する

この記事では、データベースを使用してユーザーを格納してフォーム ベースの認証を実装する方法について説明します。 これは、次の Microsoft .NET Framework クラス ライブラリ名前空間を参照します。

  • System.Data.SqlClient
  • System.Web.Security

元の製品バージョン: ASP.NET
元の KB 番号: 301240

要件

次の一覧では、必要な推奨ハードウェア、ソフトウェア、ネットワーク インフラストラクチャ、およびサービス パックの概要を示します。

  • Visual Studio .NET
  • インターネット インフォメーション サービス (IIS) バージョン 5.0 以降
  • SQL Server

C# .NET を使用して ASP.NET アプリケーションを作成する

  1. Visual Studio .NET を開きます。
  2. 新しい ASP.NET Web アプリケーションを作成し、名前と場所を指定します。

Web.config ファイルでセキュリティ設定を構成する

このセクションでは、フォーム ベースの認証を使用するように ASP.NET アプリケーションを構成するために、および <authorization> 構成セクションを追加および変更<authentication>する方法について説明します。

  1. ソリューション エクスプローラーで、Web.config ファイルを開きます。

  2. 認証モードを Forms に変更します。

  3. タグを <Forms> 挿入し、適切な属性を入力します。 次のコードをコピーし、[編集] メニューの [HTML として貼り付け] を選択して、ファイルのセクションにコードを<authentication>貼り付けます。

    <authentication mode="Forms">
        <forms name=".ASPXFORMSDEMO" loginUrl="logon.aspx"
            protection="All" path="/" timeout="30" />
    </authentication>
    
  4. 次のように、セクション内の匿名ユーザーへのアクセスを <authorization> 拒否します。

    <authorization>
        <deny users ="?" />
        <allow users = "*" />
    </authorization>
    

ユーザーの詳細を格納するサンプル データベース テーブルを作成する

このセクションでは、ユーザーのユーザー名、パスワード、ロールを格納するサンプル データベースを作成する方法について説明します。 ユーザー ロールをデータベースに格納し、ロールベースのセキュリティを実装する場合は、ロール列が必要です。

  1. [ スタート ] メニューの [ 実行] を選択し、メモ帳を入力してメモ帳を開きます。

  2. 次の SQL スクリプト コードを強調表示し、コードを右クリックし、[ コピー] を選択します。 メモ帳で、[編集] メニューの [貼り付け] を選択して、次のコードを貼り付けます。

    if exists (select * from sysobjects where id =
    object_id(N'[dbo].[Users]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
        drop table [dbo].[Users]
    GO
    CREATE TABLE [dbo].[Users] ([uname] [varchar] (15) NOT NULL,
        [Pwd] [varchar] (25) NOT NULL,
        [userRole] [varchar] (25) NOT NULL,
    ) ON [PRIMARY]
    GO
    ALTER TABLE [dbo].[Users] WITH NOCHECK ADD
        CONSTRAINT [PK_Users] PRIMARY KEY NONCLUSTERED
        ([uname]
        ) ON [PRIMARY]
    GO
    
    INSERT INTO Users values('user1','user1','Manager')
    INSERT INTO Users values('user2','user2','Admin')
    INSERT INTO Users values('user3','user3','User')
    GO
    
  3. ファイルを Users.sqlとして保存します。

  4. SQL Server コンピューターで、Query Analyzer でUsers.sqlを開きます。 データベースの一覧から [pubs] を選択し、スクリプトを実行します。 この操作により、サンプル ユーザー テーブルが作成され、このサンプル アプリケーションで使用される Pubs データベース内のテーブルが設定されます。

Logon.aspx ページを作成する

  1. Logon.aspx という名前のプロジェクトに新しい Web フォーム 追加します。

  2. エディターで [Logon.aspx] ページを開き、HTML ビューに切り替えます。

  3. 次のコードをコピーし、[編集] メニューの [HTML として貼り付け] オプションを使用して、タグ間にコードを<form>挿入します。

    <h3>
        <font face="Verdana">Logon Page</font>
    </h3>
    <table>
        <tr>
            <td>Email:</td>
            <td><input id="txtUserName" type="text" runat="server"></td>
            <td><ASP:RequiredFieldValidator ControlToValidate="txtUserName"
                Display="Static" ErrorMessage="*" runat="server" 
                ID="vUserName" /></td>
        </tr>
        <tr>
            <td>Password:</td>
            <td><input id="txtUserPass" type="password" runat="server"></td>
            <td><ASP:RequiredFieldValidator ControlToValidate="txtUserPass"
            Display="Static" ErrorMessage="*" runat="server"
            ID="vUserPass" />
            </td>
        </tr>
        <tr>
            <td>Persistent Cookie:</td>
            <td><ASP:CheckBox id="chkPersistCookie" runat="server" autopostback="false" /></td>
            <td></td>
        </tr>
    </table>
    <input type="submit" Value="Logon" runat="server" ID="cmdLogin"><p></p>
    <asp:Label id="lblMsg" ForeColor="red" Font-Name="Verdana" Font-Size="10" runat="server" />
    

    この Web フォームは、ユーザーがユーザー名とパスワードを指定してアプリケーションにログオンできるように、ログオン フォームをユーザーに提示するために使用されます。

  4. デザイン ビューに切り替えて、ページを保存します。

ユーザー資格情報を検証するようにイベント ハンドラーをコーディングする

このセクションでは、分離コード ページ (Logon.aspx.cs) に配置されるコードを示します。

  1. [ログオン] をダブルクリックして、Logon.aspx.cs ファイルを開きます。

  2. 分離コード ファイルに必要な名前空間をインポートします。

    using System.Data.SqlClient;
    using System.Web.Security;
    
  3. データベースを ValidateUser 調べることでユーザーの資格情報を検証する関数を作成します。 データベースを指す文字列を Connection 必ず変更してください。

    private bool ValidateUser( string userName, string passWord )
    {
        SqlConnection conn;
        SqlCommand cmd;
        string lookupPassword = null;
    
        // Check for invalid userName.
        // userName must not be null and must be between 1 and 15 characters.
        if ( ( null == userName ) || ( 0 == userName.Length ) || ( userName.Length > 15 ))
        {
            System.Diagnostics.Trace.WriteLine( "[ValidateUser] Input validation of userName failed." );
            return false;
        }
    
        // Check for invalid passWord.
        // passWord must not be null and must be between 1 and 25 characters.
        if ( ( null == passWord ) || ( 0 == passWord.Length ) || ( passWord.Length > 25 ))
        {
            System.Diagnostics.Trace.WriteLine( "[ValidateUser] Input validation of passWord failed." );
            return false;
        }
    
        try
        {
            // Consult with your SQL Server administrator for an appropriate connection
            // string to use to connect to your local SQL Server.
            conn = new SqlConnection( "server=localhost;Integrated Security=SSPI;database=pubs" );
            conn.Open();
    
            // Create SqlCommand to select pwd field from users table given supplied userName.
            cmd = new SqlCommand( "Select pwd from users where uname=@userName", conn );
            cmd.Parameters.Add( "@userName", SqlDbType.VarChar, 25 );
            cmd.Parameters["@userName"].Value = userName;
    
            // Execute command and fetch pwd field into lookupPassword string.
            lookupPassword = (string) cmd.ExecuteScalar();
    
            // Cleanup command and connection objects.
            cmd.Dispose();
            conn.Dispose();
        }
        catch ( Exception ex )
        {
            // Add error handling here for debugging.
            // This error message should not be sent back to the caller.
            System.Diagnostics.Trace.WriteLine( "[ValidateUser] Exception " + ex.Message );
        }
    
        // If no password found, return false.
        if ( null == lookupPassword )
        {
            // You could write failed login attempts here to event log for additional security.
            return false;
        }
    
        // Compare lookupPassword and input passWord, using a case-sensitive comparison.
        return ( 0 == string.Compare( lookupPassword, passWord, false ));
    }
    
  4. 2 つの方法のいずれかを使用して、フォーム認証 Cookie を生成し、イベント内の適切なページにユーザーを cmdLogin_ServerClick リダイレクトできます。 サンプル コードは、両方のシナリオで提供されます。 要件に従って、どちらかを使用します。

    • メソッドを RedirectFromLoginPage 呼び出してフォーム認証 Cookie を自動的に生成し、次の場合にユーザーを適切なページに cmdLogin_ServerClick リダイレクトします。

      private void cmdLogin_ServerClick(object sender, System.EventArgs e)
      {
          if (ValidateUser(txtUserName.Value,txtUserPass.Value))
              FormsAuthentication.RedirectFromLoginPage(txtUserName.Value, chkPersistCookie.Checked);
          else
              Response.Redirect("logon.aspx", true);
      }
      
    • 認証チケットを生成し、暗号化し、Cookie を作成し、応答に追加して、ユーザーをリダイレクトします。 この操作により、Cookie の作成方法をより詳細に制御できます。 この場合は、 と共にカスタム データを FormsAuthenticationTicket 含めることもできます。

      private void cmdLogin_ServerClick(object sender, System.EventArgs e)
      {
          if (ValidateUser(txtUserName.Value,txtUserPass.Value))
          {
              FormsAuthenticationTicket tkt;
              string cookiestr;
              HttpCookie ck;
              tkt = new FormsAuthenticationTicket(1, txtUserName.Value, DateTime.Now,
              DateTime.Now.AddMinutes(30), chkPersistCookie.Checked, "your custom data");
              cookiestr = FormsAuthentication.Encrypt(tkt);
              ck = new HttpCookie(FormsAuthentication.FormsCookieName, cookiestr);
              if (chkPersistCookie.Checked)
                  ck.Expires=tkt.Expiration;
              ck.Path = FormsAuthentication.FormsCookiePath;
              Response.Cookies.Add(ck);
      
              string strRedirect;
              strRedirect = Request["ReturnUrl"];
              if (strRedirect==null)
                  strRedirect = "default.aspx";
              Response.Redirect(strRedirect, true);
          }
          else
              Response.Redirect("logon.aspx", true);
      }
      
  5. Web フォーム Designerが生成するInitializeComponentコード内の メソッドに次のコードが追加されていることを確認します。

    this.cmdLogin.ServerClick += new System.EventHandler(this.cmdLogin_ServerClick);
    

Default.aspx ページを作成する

このセクションでは、ユーザーが認証後にリダイレクトされるテスト ページを作成します。 ユーザーがアプリケーションに最初にログオンせずにこのページを参照すると、ログオン ページにリダイレクトされます。

  1. 既存の WebForm1.aspx ページの名前 をDefault.aspxに変更し、エディターで開きます。

  2. HTML ビューに切り替え、タグ間で次のコードを <form> コピーします。

    <input type="submit" Value="SignOut" runat="server" id="cmdSignOut">
    

    このボタンは、フォーム認証セッションからログオフするために使用されます。

  3. デザイン ビューに切り替えて、ページを保存します。

  4. 分離コード ファイルに必要な名前空間をインポートします。

    using System.Web.Security;
    
  5. SignOut をダブルクリックして分離コード ページ (Default.aspx.cs) を開き、イベント ハンドラーで次のコードをcmdSignOut_ServerClickコピーします。

    private void cmdSignOut_ServerClick(object sender, System.EventArgs e)
    {
        FormsAuthentication.SignOut();
        Response.Redirect("logon.aspx", true);
    }
    
  6. Web フォーム Designerが生成するInitializeComponentコード内の メソッドに次のコードが追加されていることを確認します。

    this.cmdSignOut.ServerClick += new System.EventHandler(this.cmdSignOut_ServerClick);
    
  7. プロジェクトを保存してコンパイルします。 これで、アプリケーションを使用できます。

備考

  • パスワードをデータベースに安全に格納したい場合があります。 という名前HashPasswordForStoringInConfigFileのクラス ユーティリティ関数をFormsAuthentication使用して、パスワードをデータベースまたは構成ファイルに格納する前に暗号化できます。

  • 必要に応じて簡単に変更できるように、SQL 接続情報を構成ファイル (Web.config) に格納することもできます。

  • さまざまな組み合わせのパスワードを使用しようとするハッカーがログオンできないようにコードを追加することを検討できます。 たとえば、2 回または 3 回のログオン試行のみを受け入れるロジックを含めることができます。 ユーザーが一部の試行でログオンできない場合は、別のページにアクセスするか、サポートラインを呼び出して、ユーザーがアカウントを再度有効にするまでログオンできないように、データベースにフラグを設定できます。 また、必要に応じて適切なエラー処理を追加する必要があります。

  • ユーザーは認証 Cookie に基づいて識別されるため、このアプリケーションで Secure Sockets Layer (SSL) を使用して、誰も認証 Cookie やその他の重要な情報が送信されないようにすることができます。

  • フォーム ベースの認証では、クライアントがブラウザーで Cookie を受け入れるか有効にする必要があります。

  • 構成セクションの <authentication> timeout パラメーターは、認証 Cookie が再生成される間隔を制御します。 パフォーマンスとセキュリティを向上する値を選択できます。

  • インターネット上の特定の中継プロキシとキャッシュは、ヘッダーを含む Set-Cookie Web サーバー応答をキャッシュし、別のユーザーに返される場合があります。 フォーム ベースの認証では Cookie を使用してユーザーを認証するため、この動作により、もともと意図されていなかった中間プロキシまたはキャッシュから Cookie を受け取ることで、ユーザーが誤って (または意図的に) 別のユーザーになりすます可能性があります。

関連情報