WCF Sample 012その1 httpsを使用してWCFサービスをIIS7.0上で公開する では、httpsを使用して、WCFを公開する方法を掲載しました。今回はユーザ認証、アクセス制御にSqlMembershipProvider,SqlRoleProviderを使用するようにサービスの構成を変更し、クライアントからアクセスします。最後に、WCF Sample 011 と同じようにサービスへのアクセス許可を制御するサンプルを掲載します。ただし、アクセスを許可するロールはWindowsTokenRoleProviderではなく、SqlRoleProviderから制御されます。
動作確認環境
- Windows Vista Enterprise(スタンドアロン: IIS7.0からWCFサービスを公開する。WCFクライアントはコンソールアプリ)
- 開発環境 Visual Studio 2008 Enterprise
- .NET 3.5
0.前提条件
前提条件として、SqlMembershipProvider,SqlRoleProviderは使用できる構成がWCFSample012ProductServiceプロジェクトのWeb.configに作成済みであるとします。構成の仕方が不明の場合は説明のあるMSDNや書籍、Webサイトを参考にして下さい。次のユーザがデータベースに登録されているとします。
ユーザ名 | AspWcfUser |
パスワード | AspWcfUser001 |
ロール | AspWcfUsers |
Membershipプロバイダ名はAspNetSqlMembershipProvider, Roleプロバイダ名はAspNetSqlRoleProviderで構成されているとします。
1.WCFサービスがSqlRoleProviderとSqlMembershipProviderを使用するように構成する
資格情報,ロール情報にSqlMembershipProviderとSqlRoleProviderを使用するように構成します。
WCFSample012ProductServiceプロジェクトのWeb.configをWCF Service Configuration Editorで編集します。左側ペインの[Advanced]→[Service Behavior]→ProductServiceBehaviorを選択し、右側ペインの[Add]ボタンをクリックし、表示されるAdding Behavior Element Extention SectionsダイアログからserviceAuthorizationとserviceCredentialsを選択して[Add]ボタンクリックしてBehaviorを追加する。

左側ペインの追加されたserviceAuthorizationを選択する。右ペインのPrincipalPermissionModeをUseWindowsGroupsからUseAspNetRolesとし、RoleProviderNameにAspNetSqlRoleProviderとします。この設定でユーザの所属するロールの情報としてWindowsのセキュリティグループではなくMemberShipPvoviderのロール情報を使用するようになります。
AspNetSqlRoleProviderはmachine.configに定義されているデフォルトのプロバイダ名ですが、connectionStringNameがLocalSqlServerではないなど、プロバイダの構成に変更が必要な場合はWeb.configで再定義する必要があります。下記例参照
定義例:
<roleManager enabled="true" defaultProvider="AspNetSqlRoleProvider">
<providers>
<clear/>
<add name="AspNetSqlRoleProvider" connectionStringName="AspNetSqlConnection" applicationName="/"
type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
</providers>
</roleManager>

次に、追加されたserviceCredentialsを選択し、右側ペインのUserNamePasswordValidationModeをMembershipProviderにセットし、MembershipProviderNameにAspNetSqlMembershipProviderを指定します。この設定によりユーザの認証にWindowsのユーザではなくMembershipProviderのユーザを使用するようになります。
AspNetSqlMembershipProviderはmachine.configに記載されているSqlMembershipProviderを使用するMembershipProviderの設定です。connectionStringNameがLocalSqlServerではないなどプロバイダの設定に変更がある場合はWeb.configで再定義します。以下設定例
<membership defaultProvider="AspNetSqlMembershipProvider">
<providers>
<clear/>
<add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="AspNetSqlConnection"
enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="true"
applicationName="/" requiresUniqueEmail="false" passwordFormat="Hashed" maxInvalidPasswordAttempts="5"
minRequiredPasswordLength="7" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10"
passwordStrengthRegularExpression=""/>
</providers>
</membership>

変更内容を上書き保存して、Configuration Editorを終了します。
2.WCFクライアントの作成
2.1 App.configの構成を変更
WCFSample.ConsoleClientのApp.configをWCF Service Configuration Editorで編集します。左のペインのBindingsを右クリックし新規作成します。最初に表示されるダイアログでwsHttpBindingを選択して[OK]をクリックします。右側ペインのNameをWSHttpBinding_ProductServiceにします。SerucityタブをクリックしてModeをWCFサービスと同じTransportWithMessageCredentialに設定し、MessageClientCredentialTypeをUserNameにセットし、TransportClientCredentialTypeをNoneに設定します。

左側ペインのClient→Endpoints→BasicHttpBinding_ProductServiceを選択。右側ペインのBindingにwsHttpBindingを選択し、BindingConfigurationにWSHttpBinding_ProductServiceを選択する。Addressにhttps://localhost/WCFSample012/ProductService.svcを入力します。変更内容を保存して終了します。
2.2 クライアントプログラムの修正
WCFSample.ConsoleClientのProgram.csを変更します。SSLで使用する証明書は信頼されていない証明期間(自己証明書)から発行されているので、証明書に問題がある場合も、確認メッセージを表示して処理を続行するかを決めるクラスを追加します。
/// <summary> /// 証明書に問題がある場合は確認するポリシークラス /// </summary> class ConfirmCertificatePolicy { public ConfirmCertificatePolicy() { ServicePointManager.ServerCertificateValidationCallback += RemoteCertValidation; } bool RemoteCertValidation(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors error) { if (error != SslPolicyErrors.None) { Console.WriteLine("証明書に問題があります。理由:" + chain.ChainStatus[0].StatusInformation); Console.Write("処理を続行しますか? y:続行:"); string input = Console.ReadLine(); if (input.ToLower() == "y") return true; else return false; } return true; } }
次に、Mainメソッドの最初にConfirmCertificatePolicyクラスのインスタンスを作成するコードを追加し、サービスメソッドを呼び出す前にプロキシクラスにユーザの資格情報を入力するコードを追加します。
static void Main(string[] args) { ConfirmCertificatePolicy policy = new ConfirmCertificatePolicy(); // 証明書続行確認用 System.Console.WriteLine("WCFサービスホストを起動したら、キーを入力して下さい。"); System.Console.ReadLine(); ProductServiceClient proxy = new WCFSample.Client.Proxy.ProductServiceClient("BasicHttpBinding_ProductService"); proxy.ClientCredentials.UserName.UserName = "AspWcfUser"; // ユーザID proxy.ClientCredentials.UserName.Password = "AspWcfUser001"; // パスワード int[] productIDs = proxy.GetProductIDs(); foreach (int productID in productIDs) { Console.WriteLine("Product ID: " + productID); Product product = proxy.GetProductByID(productID); Console.WriteLine("Name: " + product.Name); Console.WriteLine("Color: " + product.Color); Console.WriteLine("ListPrice: " + product.ListPrice); } proxy.Close(); Console.WriteLine("終了するにはなにかキーを押してください。"); Console.ReadLine(); }
以上で修正は完了です。
スタートアッププロジェクトにWCFSample.ConsoleClientを指定してデバッグ実行を行うと、コンソールに証明書が不正で続行するかの確認メッセージが表示されます。yを入力するとプログラムが続行されます。
3.サービスメソッドにアクセス制御を設定する
PrincipalPermissionAttributeを使用している場合は、Windowsのセキュリティグループを使用している場合と同じで次のようにサービスクラスのサービスメソッドに属性を付与します。以下の例はGetProductIDs()サービスメソッドのアクセス可能なロールにAspWcfUsersを指定する場合。
[PrincipalPermission(SecurityAction.Demand, Role = "AspWcfUsers")]
public List<int> GetProductIDs()
{..}
同様の処理をサービスメソッド内で行い場合は以下のように記述します。
public List<int> GetProductIDs()
{
IIdentity user = System.ServiceModel.ServiceSecurityContext.Current.PrimaryIdentity;
if (!(System.Web.Security.Roles.IsUserInRole("AspWcfUsers")))
{
throw new System.Security.SecurityException("Access Denied");
}
..
}