web-dev-qa-db-ja.com

WCFを使用した基本認証でWebサービスを呼び出すことはできません

Javaで記述された、変更を加えることができないWebサービスが提供されました。どのメソッドにもアクセスするには、ユーザーが基本認証で認証する必要があります。推奨される方法.NETでこのサービスを操作するには、WSE3.0がインストールされたVisualStudio2005を使用します。

プロジェクトはすでにVisualStudio 2008(.NET 2.0を対象としている)を使用しているため、これは問題です。 VS2005でそれを行うことはできますが、プロジェクトをVS2005に結び付けたり、VS2005でアセンブリを作成し、それをVS2008ソリューションに含めたりすることはしたくありません(基本的に、アセンブリへの将来の変更のためにプロジェクトを2005に結び付けます)。これらのオプションのいずれかを使用すると、新しい開発者はWSE 3.0をインストールし、プロジェクトで2008と.NET 3.5の機能を将来使用できなくなるため、作業が複雑になると思います。つまり、WCFを使用すると本当に信じています。行く方法です。

これにWCFを使用することを検討してきましたが、WCFサービスに、各要求とともに認証ヘッダーを送信する必要があることを理解させる方法がわかりません。 Webサービスで何かをしようとすると、401エラーが発生します。

これは私のコードがどのように見えるかです:

WebHttpBinding webBinding = new WebHttpBinding();
ChannelFactory<MyService> factory = 
     new ChannelFactory<MyService>(webBinding, new EndpointAddress("http://127.0.0.1:80/Service/Service/"));
factory.Endpoint.Behaviors.Add(new WebHttpBehavior());
factory.Credentials.UserName.UserName = "username";
factory.Credentials.UserName.Password = "password";

MyService proxy = factory.CreateChannel();
proxy.postSubmission(_postSubmission);

これが実行され、次の例外がスローされます。

HTTP要求は、クライアント認証スキーム「匿名」では許可されていません。サーバーから受信した認証ヘッダーは「基本レルム=レルム」でした。

そして、これには次の内部例外があります。

リモートサーバーがエラーを返しました:(401)Unauthorized。

この問題の原因について考えていただければ幸いです。

15
Rex Morgan

最初の質問:これはSOAPまたはa RESTベースのJavaあなたが呼び出そうとしているサービスですか?

現在、「webHttpBinding」では、RESTベースのアプローチを使用しています。 JavaサービスがSOAPサービスの場合、代わりにバインディングを「basicHttpBinding」に変更する必要があります。

[〜#〜] if [〜#〜]これはSOAPベースのサービスです。これを試してください:

BasicHttpBinding binding = new BasicHttpBinding();

binding.SendTimeout = TimeSpan.FromSeconds(25);

binding.Security.Mode = BasicHttpSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = 
                              HttpClientCredentialType.Basic;

EndpointAddress address = new EndpointAddress(your-url-here);

ChannelFactory<MyService> factory = 
             new ChannelFactory<MyService>(binding, address);

MyService proxy = factory.CreateChannel();

proxy.ClientCredentials.UserName.UserName = "username";
proxy.ClientCredentials.UserName.Password = "password";

私はこれをさまざまなWebサービスで使用してきましたが、ほとんどの場合は機能します。

それが機能しない場合は、そのJava Webサービスが期待するものと、その関連情報をWebサービスに送信する方法について詳しく知る必要があります。

マーク

28
marc_s

まず、app.configまたはweb.configに次のものを入れます。 (環境内を移動するときにこれを変更する必要はありません):

<system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="BasicHttpBinding_IConfigService">
                    <security mode="TransportCredentialOnly">
                        <transport clientCredentialType="Basic"/>
                    </security>
                </binding>
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:55283/ConfigService.svc"
                binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IConfigService"
                contract="IConfigService" name="BasicHttpBinding_IService" />
        </client>
    </system.serviceModel>

それに応じて、コントラクト属性をNamespace.Interface名に変更します。セキュリティモードに注意してください= TransportCredentialOnly

プログラムでエンドポイントを変更して資格情報を渡すには、次のコードを使用します。

            var myBinding = new BasicHttpBinding("BasicHttpBinding_IConfigService");
            var myEndpoint = new EndpointAddress("http://yourbaseurl/configservice.svc");
            var myChannelFactory = new ChannelFactory<IConfigService>(myBinding, myEndpoint);

            var credentialBehaviour = myChannelFactory.Endpoint.Behaviors.Find<ClientCredentials>();
            credentialBehaviour.UserName.UserName = @"username";
            credentialBehaviour.UserName.Password = @"password";

            IConfigService client = null;

            try
            {
                client = myChannelFactory.CreateChannel();
                var brands = client.YourServiceFunctionName();
                ((ICommunicationObject)client).Close();
            }
            catch (Exception ex)
            {
                if (client != null)
                {
                    ((ICommunicationObject)client).Abort();
                }
            }
7
jaxxbo

私が今経験した同様の問題に基づいて、これにも追加します。 VSを使用して構成/プロキシを自動生成しましたが、作成した構成は実際には機能しませんでした。

セキュリティモード= "Transport"が正しく設定されていましたが、clientCredentialType = "Basic"が設定されていませんでした。それに自分の設定を追加しましたが、それでも機能しませんでした。次に、連絡しているサービスがSSL + Basicのみであるため、ツールが作成したメッセージセキュリティを実際に削除しました。

<message clientCredentialType="UserName" algorithmSuite="Default" />

出来上がり-それはうまくいった。

要素がメッセージレベルのセキュリティを指定しなかったことを考えると、なぜこれが効果を発揮したのかわかりません...しかし、効果はありました。

3
Ethan J. Brown