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

17

我收到了一个用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请求未经客户端身份验证方案“匿名”授权。从服务器收到的身份验证标头为“Basic realm=realm”。

并且它还有一个内部异常:

远程服务器返回错误:(401) 未经授权。

请问您认为可能是什么原因导致了这个问题?非常感谢。

3个回答

29

首先问题是:您尝试调用的是基于SOAP还是REST的Java服务?

目前,通过"webHttpBinding",您正在使用基于REST的方法。如果Java服务是SOAP服务,则需要将绑定更改为"basicHttpBinding"。

如果这是一个基于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服务期望什么以及如何向其发送相关信息。

Marc


3
在我输入代理之后,属性ClientCredentials根本没有出现。 - rajibdotnet
1
@rajibdotnet:嗯,问题中的代码基本上就是你需要调用基于REST的服务的内容...如果这不够帮助,请提出你自己的问题,这样大家才能回答... - marc_s
@marc_s,这在Java中的等效物是什么?我还收到了一个使用此种身份验证方式的示例Web服务客户端...我需要将其转换为Java。 - Sergiu
@Sergiu:抱歉,我不太了解Java,无法为您转换。 - marc_s
在 "ChannelFactory<MyService>" 中,应该用什么代替 "MyService"? - Mayur Patel
显示剩余2条评论

8

首先将以下内容放入您的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>

根据命名空间和接口名称相应地更改合同属性。请注意,安全模式为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();
                }
            }

我不明白credentialBehavior是如何应用于Channel的?看起来你只是通过Find<>查找客户端凭据并将其应用于新的Var credentialBehavior。然后,您设置该变量的用户名和密码...如果我没有错,那与绑定无关。 - SoftwareSavant

3

我会根据我最近遇到的一个类似问题进行补充。我使用VS自动生成了配置/代理,但它创建的配置实际上无法正常工作。

尽管它正确设置了security mode="Transport",但它没有设置clientCredentialType="Basic"。我在我的配置中添加了这个,但它仍然不起作用。然后,我实际上删除了工具创建的消息安全性,因为我要连接的服务仅支持SSL + Basic:

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

看,它起作用了。

我不确定为什么会有影响,因为这个元素没有指定消息级别的安全性...但它确实起作用了。


我收到了“未知的属性'algorithmSuite'”的错误提示,无法正常工作。客户端使用Windows 10上的Visual Studio 2017,服务器端不明确。 - gridtrak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接