ASP.NETのフォーム認証とロールでのアクセス制御[ASP.NET固有]

サイトの管理ページにフォーム認証を実装してみました。


やりたいことは、
1)ページ全体への認証
2)特定ページへのアクセス制限
です。


すでに、DBに認証用テーブルがあるので、
1)に関してはMembershipProviderを継承したクラスで、
2)に関してはRoleProviderを継承したクラスでロールで管理するよう実装します。


まず1)から。

Public Class MyMembershipProvider
    Inherits MembershipProvider

    Public Overrides Function ValidateUser(ByVal username As String, ByVal password As String) As Boolean

        '入力されたusernameとpaswordを元に、認証が正しいかチェキ

    End Function

    '他のMustInheritなFunctionは使わないので、全てThrow New NotSupportedExceptionする

End Class


ルートのweb.configに、上記クラスを使用するように設定を記述

<configuration>
  <system.web>
    <!--非認証ユーザをログインページへ誘導-->
    <authentication mode="Forms">
      <forms loginUrl="~/login.aspx" />
    </authentication>
    <!--認証情報管理クラス-->
    <membership defaultProvider="MyMembershipProvider">
      <providers>
        <add name="MyMembershipProvider" type="MyMembershipProvider"/>
      </providers>
    </membership>
  </system.web>
</configuration>


次に、login.aspxを作成します。
IDとパスワードのテキストボックスを配置し、ログインボタンを押された際に認証します。

Partial Class Login
    Inherits MyAdminPage

    Protected Sub btnLogin_Click(ByVal sender As Object, ByVal e As System.Web.UI.ImageClickEventArgs) Handles btnLogin.Click

        '入力されたIDとパスの値をチェキ
        
        '次に、'ログインチェック
        'Membership.ValidateUserを呼ぶと、MyMembershipProvider.ValidateUserが呼び出されます。
        If Membership.ValidateUser(txtUser.Text, txtPass.Text) Then
            '認証OKであれば、遷移する。
            FormsAuthentication.RedirectFromLoginPage(txtUser.Text, False)
        End If

    End Sub

End Class


あとは、認証をかけたいディレクトリのweb.configに以下を追加

<configuration>
    <appSettings/>
    <connectionStrings/>
    <system.web>
      <authorization>
        <deny users="?"/>
      </authorization>
    </system.web>
</configuration>

login.aspxにて、FormsAuthentication.RedirectFromLoginPageを呼び出したときのリダイレクト先が、
クエリストリングのReturnURLにならず、規定のURLにしかりダイレクトされないという現象に悩んだ。
原因は簡単で、ページの

のaction属性にlogin.aspxとべた書きしてしまっていた為、ReturnURLの値が消えてしまっていた。
なぜaction属性なんか書いたんだ。。。


次に2)を。
まずRoleProviderを実装するクラスを作成します。

Public Class MyRoleProvider
    Inherits RoleProvider

    '資格情報を取得
    Public Overrides Function GetRolesForUser(ByVal username As String) As String()

        '入力されたusernameを元に、ユーザのロールを取得
        'ユーザが属しているロールをString配列にして返す。("Admin"やらいろいろ)

    End Function

    '他のMustInheritなFunctionは使わないので、全てThrow New NotSupportedExceptionする

End Class


ルートのweb.configに、上記クラスを使用するように設定を記述

<configuration>
  <system.web>
    <!--ロール情報管理クラス-->
    <roleManager enabled="true" defaultProvider="MyRoleProvider">
      <providers>
        <add name="MyRoleProvider" type="MyRoleProvider"/>
      </providers>
    </roleManager>
  </system.web>
</configuration>


あとは、特定のロールに属するユーザのみの閲覧を許可したいページに対して、
上記のロールでのアクセス制御を有効にする。
認証をかけたいディレクトリのweb.configに以下を追加。

<configuration>
    <appSettings/>
    <connectionStrings/>
    <system.web>
      <authorization>
        <allow roles="Admin"/>
        <deny users="*"/>
      </authorization>
    </system.web>
</configuration>


以上で、フォーム認証とロールでのアクセス制御ができるようになりました。

ただ、複数のweb.configに設定を書くと、管理がしにくいので、
ルートのweb.configに下記のように書くようにした。

<configuration>
    <appSettings/>
    <connectionStrings/>
    <system.web>
      <authorization>
        <deny users="?"/>
      </authorization>
    </system.web>
  
  <!--Adminというサブディレクトリへの設定-->
  <location path="Admin">
    <system.web>
      <authorization>
        <allow roles="Admin"/>
        <deny users="*"/>
      </authorization>
    </system.web>
  </location>
  
  <!--Testerというサブディレクトリへの設定-->
  <location path="Tester">
    <system.web>
      <authorization>
        <allow roles="Tester"/>
        <deny users="*"/>
      </authorization>
    </system.web>
  </location>
</configuration>