[ASP.NET]MembershipProviderにMySQLを使う

| トラックバック(0)

ASP.NETで提供されているメンバーシップのデータソースにMySQLを使おうとすると、何かと問題に激突しやすい。ので、ちゃんと動ける状態になるまで苦労して解決した内容のメモ。


1. やりたいこと

MembershipProvider, RoleProvider, ProfileProviderを使いユーザー認証とユーザー情報管理の仕組みをサイトに取り入れる。その際、メンバー情報の格納先はMySQLサーバーとする。

2. 検証方法

ASP.NETに付属する「Webサイト管理ツール」を使用。このツール内でユーザーやロールの追加・編集等ができれば問題ないものとする。

3. MembershipProviderの準備

MembershipProviderでMySQLをデータソースとするには、Web.configの各セクションの既定のプロバイダ(defaultProvider)の属性を変更する。

<configuration>
  <system.web>

    <membership defaultProvider="MySQLMembershipProvider" />

    <profile defaultProvider="MySQLProfileProvider" enabled="true" />

    <roleManager defaultProvider="MySQLRoleProvider" enabled="true" />

  </system.web>
</configuration>

これで、Webサイト管理ツールを起動し、セキュリティタブへ移動すると、ユーザーの追加や管理が可能になる・・・・わけではなかった。

まずひっかかったのが、「選択されたデータ ストアに問題があります。・・・Unable to initialize provider. Missing or incorrect schema.」というエラーメッセージ。プロバイダの初期化が出来ない、と叱られる。

この段階ではまだMySQLサーバーにユーザー情報を格納するためのテーブルが存在していない。が、MySQLMembershipProviderは必要なテーブルを自動で作成してくれない。

これを解決するには、MySQLMembershipProviderの設定に、テーブルを自動で作成するための属性「autogenerateschema="true"」が必要になる。この属性はマシンのweb.configに書いても良いが、マシンのweb.configに手が届かない環境の場合もある。

そこで、サイトのweb.configを次のように書き換える。

<configuration>
  <system.web>

    <membership defaultProvider="MySQLMembershipProvider">
      <providers>
        <remove name="MySQLMembershipProvider" />
        <add name="MySQLMembershipProvider"
             autogenerateschema="true"
             type="MySql.Web.Security.MySQLMembershipProvider, MySql.Web, Version=6.1.2.0,
                   Culture=neutral, PublicKeyToken=c5687fc88969c44d"
             connectionStringName="LocalMySqlServer"
             applicationName="/"
             enablePasswordRetrieval="false"
             enablePasswordReset="true"
             requiresQuestionAndAnswer="true"
             requiresUniqueEmail="false"
             passwordFormat="Hashed"
             maxInvalidPasswordAttempts="5"
             minRequiredPasswordLength="7"
             minRequiredNonalphanumericCharacters="1"
             passwordAttemptWindow="10"
             passwordStrengthRegularExpression="" />
      </providers>
    </membership>

    <profile defaultProvider="MySQLProfileProvider" enabled="true" />

    <roleManager defaultProvider="MySQLRoleProvider" enabled="true" />

  </system.web>
</configuration>

プロバイダセクションで一度MySQLMembershipProviderをremoveしているのはマシンのweb.configに書かれた設定を上書きするため。異なるプロバイダ名にするのであればremoveしなくてもよい。ただしその場合はdefaultProviderの値も変えることを忘れないように。

また、type属性で指定しているMySQL.Webアセンブリのバージョンや公開キートークンなどは、稼働するサーバーのバージョンに合わせる必要がある。その他、設定値は実装状況によって適宜調整する。

4. 接続文字列

各プロバイダでは使用する接続文字列を接続文字列名で指定できる。MembershipProviderはその性質上、接続文字列内でデータベース(スキーマ)を指定しなければならないため、マシンのweb.configに書かれた接続文字列を書き換えることはできない。

そこで、connectionStringsセクションでMySQLの接続文字列を上書きするように書き換える。無論、ここも異なる接続文字列名を使うのであればremoveは必要ない。

<configuration>

  <connectionStrings>
    <remove name="LocalMySqlServer"/>
    <add providerName="MySql.Data.MySqlClient" name="LocalMySqlServer"
            connectionString="Datasource=[HostName];Database=[SchemaName];uid=[UserName];"/>
  </connectionStrings>

  <system.web>

    <membership defaultProvider="MySQLMembershipProvider">
      <providers>
        <remove name="MySQLMembershipProvider" />
        <add name="MySQLMembershipProvider"
             autogenerateschema="true"
             type="MySql.Web.Security.MySQLMembershipProvider, MySql.Web, Version=6.1.2.0,
                   Culture=neutral, PublicKeyToken=c5687fc88969c44d"
             connectionStringName="LocalMySqlServer"
             applicationName="/"
             enablePasswordRetrieval="false"
             enablePasswordReset="true"
             requiresQuestionAndAnswer="true"
             requiresUniqueEmail="false"
             passwordFormat="Hashed"
             maxInvalidPasswordAttempts="5"
             minRequiredPasswordLength="7"
             minRequiredNonalphanumericCharacters="1"
             passwordAttemptWindow="10"
             passwordStrengthRegularExpression="" />
      </providers>
    </membership>

    <profile defaultProvider="MySQLProfileProvider" enabled="true" />

    <roleManager defaultProvider="MySQLRoleProvider" enabled="true" />

  </system.web>
</configuration>

5. データベースユーザーの権限

次に、データベースのユーザーにテーブルを作成する権限を与える。面倒であれば、一度管理者権限を持つユーザーを設定してテーブルを作った後、ゲスト用ユーザーに書き戻しても構わない。

いろいろと検証した結果、メンバーシップに関係するテーブルを準備するには、MySQLユーザーに次の権限が必要となることが分かった。

  • SELECT
  • INSERT
  • UPDATE
  • DELETE
  • CREATE
  • DROP
  • ALTER

SELECT, INSERT, UPDATE, DELETEはユーザーの作成や管理に必要である。それ以降のCREATE, DROP, ALTERは、最初にテーブルを作るときだけ必要になる。DROPやALTERが必要なのは、一度テーブルを作り、それをリネームしているような動作があるので、必要になるのだろう。

ここまでくれば、テーブルの作成・初期化が行われるようになり、Webサイト管理ツールでユーザーやロールの管理が使用できるようになる。ツールがエラーを吐かなければ、MySQLの指定したデータベースには「my_aspnet_」ではじまるテーブルが9つできているはずである。

おまけ

MembershipProviderには、ひとつのデータベースで複数のWebアプリケーションのユーザーが管理できるように設計されている。特に、レンタルサーバーなどで使用できるデータベース数が限られている場合は重宝するでしょう。

各プロバイダの属性には「applicationName」があるので、この名前を変更することで、ひとつのデータベースを共有できるようになる。こうなると、すべてのプロバイダ設定をカスタマイズする必要が出てくるので、最終的にweb.configは次のような形になる。

<configuration>

  <connectionStrings>
    <remove name="LocalMySqlServer"/>
    <add providerName="MySql.Data.MySqlClient" name="LocalMySqlServer"
            connectionString="Datasource=[HostName];Database=[SchemaName];uid=[UserName];"/>
  </connectionStrings>

  <system.web>

    <membership defaultProvider="MySQLMembershipProvider">
      <providers>
        <remove name="MySQLMembershipProvider" />
        <add name="MySQLMembershipProvider"
             autogenerateschema="true"
             type="MySql.Web.Security.MySQLMembershipProvider, MySql.Web, Version=6.1.2.0,
                   Culture=neutral, PublicKeyToken=c5687fc88969c44d"
             connectionStringName="LocalMySqlServer"
             applicationName="WebApp01"
             enablePasswordRetrieval="false"
             enablePasswordReset="true"
             requiresQuestionAndAnswer="true"
             requiresUniqueEmail="false"
             passwordFormat="Hashed"
             maxInvalidPasswordAttempts="5"
             minRequiredPasswordLength="7"
             minRequiredNonalphanumericCharacters="1"
             passwordAttemptWindow="10"
             passwordStrengthRegularExpression="" />
      </providers>
    </membership>

    <profile defaultProvider="MySQLProfileProvider" enabled="true">
      <providers>
        <remove name="MySQLProfileProvider"/>
        <add name="MySQLProfileProvider"
                type="MySql.Web.Profile.MySQLProfileProvider, MySql.Web, Version=6.1.2.0,
                      Culture=neutral, PublicKeyToken=c5687fc88969c44d"
                connectionStringName="LocalMySqlServer"
                applicationName="WebApp01" />
      </providers>
    </profile>

    <roleManager defaultProvider="MySQLRoleProvider" enabled="true">
      <providers>
        <remove name="MySQLRoleProvider"/>
        <add name="MySQLRoleProvider"
                type="MySql.Web.Security.MySQLRoleProvider, MySql.Web, Version=6.1.2.0,
                      Culture=neutral, PublicKeyToken=c5687fc88969c44d"
                connectionStringName="LocalMySqlServer"
                applicationName="WebApp01" />
      </providers>
    </roleManager>

  </system.web>
</configuration>

トラックバック(0)

トラックバックURL: /mt/mt-tb.cgi/64