WCF客户端使用证书和用户名/密码凭据?

时间:2009-07-22 12:57:10

标签: wcf wcf-security

我从ASP.NET使用我公司内部的Web服务。我已经使用svcutil.exe连接到服务并从wsdl生成绑定和类。我能够连接到开发版本,不需要身份验证。现在我们正在增加安全性。我的新URI使用https,但也需要用户凭据。

我对WCF很新,我正在尝试确定配置它的方法。从我的reading on MSDN开始,似乎可以使用。

更新: 这是我一直在尝试的最新代码。这包含了答案的反馈:

 <system.serviceModel>
   <behaviors>
     <serviceBehaviors>
       <behavior name="svcBehavior">
         <serviceCredentials>
           <serviceCertificate storeLocation="CurrentUser"
                               storeName="My"
                               x509FindType="FindByThumbprint"
                               findValue="xx xx xx etc"/>
         </serviceCredentials>
       </behavior>
     </serviceBehaviors>
   </behaviors>
   <bindings>
     <wsHttpBinding>
       <binding name="CustomerPaymentProgramSOAPBinding">
         <security mode="TransportWithMessageCredential">
            <message clientCredentialType="UserName" />
         </security>
       </binding>
     </wsHttpBinding>
   </bindings>
  <client>
   <endpoint address="https://***URL***"
    binding="wsHttpBinding" bindingConfiguration="CustomerPaymentProgramSOAPBinding"
    contract="CppService.CustomerPaymentProgramService" name="CustomerPaymentProgramService">
   </endpoint>
  </client>
 </system.serviceModel>

这是调用代码:

using (var svc = new CustomerPaymentProgramServiceClient())
{
    svc.ClientCredentials.UserName.UserName = "*******";
    svc.ClientCredentials.UserName.Password = "*******";
    var request = new GetServiceDataProgramRequest()
                      {
                          CustomerAccountId = Convert.ToInt64(customerAccountId)
                      };

    svc.Open();
    var response = new GetServiceDataProgramResponse();
    var metaData = new RequestMetadata()
                       {
                           ClientIPAddress = "xx.xx.xx.xx",
                           TrackingNumber = "1",
                           UserID = "1"
                       };

    svc.GetAccountData(metaData, request, out response);
}

我收到一条错误消息,指出我正在通过请求传递匿名凭据。 使用更新的代码,现在我收到了一个不同的例外:

更新:

在进行建议的更改以及从using块中删除服务调用后(this文章),我现在收到MessageSecurityException:

Error message:
-$exception {"The HTTP request is unauthorized with client authentication scheme 'Anonymous'. 
The authentication header received from the server was 'Basic realm=\"Spring Security Application\"'."} 
System.Exception {System.ServiceModel.Security.MessageSecurityException}


Server stack trace: 
at System.ServiceModel.Channels.HttpChannelUtilities.ValidateAuthentication(HttpWebRequest request, HttpWebResponse response, WebException responseException, HttpChannelFactory factory)
at System.ServiceModel.Channels.HttpChannelUtilities.ValidateRequestReplyResponse(HttpWebRequest request, HttpWebResponse response, HttpChannelFactory factory, WebException responseException)
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Channels.SecurityChannelFactory`1.SecurityRequestChannel.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Security.SecuritySessionSecurityTokenProvider.DoOperation(SecuritySessionOperation operation, EndpointAddress target, Uri via, SecurityToken currentToken, TimeSpan timeout)
at System.ServiceModel.Security.SecuritySessionSecurityTokenProvider.GetTokenCore(TimeSpan timeout)
at System.IdentityModel.Selectors.SecurityTokenProvider.GetToken(TimeSpan timeout)
at System.ServiceModel.Security.SecuritySessionClientSettings`1.ClientSecuritySessionChannel.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.CallOpenOnce.System.ServiceModel.Channels.ServiceChannel.ICallOnce.Call(ServiceChannel channel, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.CallOnceManager.CallOnce(TimeSpan timeout, CallOnceManager cascade)
at System.ServiceModel.Channels.ServiceChannel.EnsureOpened(TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)\r\n\r\nException rethrown at [0]: 
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
at [ServiceName].GetAccountData(svcRequest request)
at [ServiceName].GetAccountData(GetAccountDataRequest request) 
    in c:\\[Project]\\service references\\[ServiceName]\\reference.cs:line 3480
at c:\\[Project]\\service references\\[ServiceName](RequestMetadata RequestMetadata, ServiceRequest, ServiceResponse& ServiceResponse) 
    in c:\\[Project]\\service references\\[ServiceName]\\reference.cs:line 3487
at c:\\[Project]\\service references\\[ServiceName].CheckAccountForPaymentPlan(String customerAccountId) 
    in c:\\[Project]\\service references\\[ServiceName]\\\\PlanCheckService.cs:line 32

1 个答案:

答案 0 :(得分:8)

使用TransportWithMessageCredential,您将指定使用邮件安全性来保护单个邮件,这需要客户端凭据(用户名和密码)。您需要与msdn链接中的配置类似的内容,如下所示:

<wsHttpBinding>
<binding name="WsHttpBinding_ICalculator">
        <security mode="TransportWithMessageCredential" >
           <message clientCredentialType="UserName" />
        </security>
</binding>
</wsHttpBinding>

这不需要为客户端凭据指定证书。传输安全性(使用https和有效的ssl证书)的工作方式与网站相同,不需要用户提供额外的凭据/证书。来自可信证书颁发机构的有效证书安装在服务器上(客户端计算机能够验证它们),并且握手过程可以保护通道。这不需要您在配置中设置clientCrdentials。您只需要安装一个有效的证书(或dev的测试证书)并配置服务器配置以指向它类似于:

<behaviors>
 <serviceBehaviors>
   <behavior name="mySvcBehavior">
       <serviceCredentials>
         <serviceCertificate findValue="contoso.com"
                             x509FindType="FindByIssuerName" />
       </serviceCredentials>
   </behavior>
 </serviceBehaviors>
</behaviors>

尝试从服务器配置中删除< transport clientCredentialType="Certificate" />作为启动器,更新服务引用并确保您的证书正常运行和配置。如果您仍有问题,请发布您的实际例外和更多配置。

对于一个好的WCF源代码尝试:CodePlex,当我开始使用WCF时,它帮助我完成了任务。不同的应用程序方案提供了有用的清单,以帮助确保您不会错过配置中的任何步骤。

祝你好运

更新:

一旦某个频道出现故障,就需要重新创建,因为在重置之前您将无法与该服务进行通信。所以添加一个检查来重新创建它:

If svc.State = CommunicationState.Faulted Then....

尝试删除svc.Open()行,因为我从未真正使用过该行。我检查了msdn的使用细节,但得到了大约2行无用的信息。设置服务后,您应该能够与其进行通信,而无需专门打开它。不确定这实际上会有所作为吗?!

要检查的其他事项: - 你能直接点击服务并在浏览器中查看吗? - 在IIS中,您可以在目录安全性中查看证书而不会出现任何问题吗? - 调试到服务调用之前的点,并检查凭据是否正确分配。 - 检查服务器事件查看器,查看它可能记录在请求中的任何信息(如果它已经到了那么远)。

此外,以下是我使用ex.GetBaseException.GetType确定问题的一些例外:

ServiceModel.EndpointNotFoundException

  • 服务器连接问题 - IIS未运行或服务器名称无效

ServiceModel.Security.MessageSecurityException

  • 基本例外 - ServiceModel.FaultException

    • FailedAuthentication” - 用户输入的凭据错误

    • InvalidSecurity” - 数据库错误 - 帐户无权访问数据库,网络配置中的数据库名称不正确,用户密码已在数据库中过期

    • InvalidRequest” - 证书可访问性问题 - 检查服务帐户是否可以访问证书

基本例外 - Net.WebException

  • 未经授权的访问401 - 检查IIS中的匿名访问是否已打开

基本例外 - IdentityModel.Tokens.SecurityTokenValidationException

  • IIS中未分配服务证书

基本例外 - System.ServiceModel.CommunicationException

  • 身份与服务器证书不匹配 - 例如在开发环境中,名为“localhost”的证书,因此如果您输入PC号码或服务的IP地址,您将看到此