无法使用WCF使用基本身份验证调用Web服务

时间:2009-09-01 23:32:27

标签: wcf web-services .net-3.5 wcf-security

我已经获得了一个用Java编写的Web服务,我无法对其进行任何更改。它要求用户通过基本身份验证进行身份验证才能访问任何方法。在.NET中与此服务交互的建议方法是使用安装了WSE 3.0的Visual Studio 2005。

这是一个问题,因为该项目已经在使用Visual Studio 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)未经授权。

对于可能导致此问题的任何想法将不胜感激。

3 个答案:

答案 0 :(得分:27)

第一个问题:这是您尝试调用的SOAP或基于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服务所期望的内容以及如何向其发送相关信息。

马克

答案 1 :(得分:7)

首先在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>

相应地将contract属性更改为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();
                }
            }

答案 2 :(得分:3)

我将根据我刚刚遇到的类似问题添加此内容。我使用VS自动生成了配置/代理 - 但是它创建的配置实际上并不起作用。

虽然正确设置了安全模式=“传输”,但它没有设置clientCredentialType =“Basic”。我添加了我的配置,它仍然无法正常工作。然后我实际上删除了工具创建的消息安全性,因为我正在联系的服务只是SSL + Basic:

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

Voila - 它奏效了。

我不确定为什么这会产生影响,因为该元素没有指定消息级安全性......但确实如此。