首页 > 解决方案 > 带有用户名身份验证的 WCF 中的异常

问题描述

我正在尝试使用自定义用户名和密码身份验证对 WCF 进行身份验证。我按照Microsoft 的本教程进行操作。在本地开发中,一切正常,但是一旦部署在服务器中,我就无法连接到该服务。每当我尝试访问服务中的方法时,它都会在客户端中引发此异常:

与对端的安全协商出错,无法打开安全通道。这可能是因为在用于创建通道的 EndpointAddress 元素中缺少 EndpointIdentity 或未正确指定。验证 EndpointAddress 中指定或隐含的 EndpointIdentity 元素是否正确标识了远程端点。

看来我已经完成了所需的一切。首先,我使用以下 PowerShell 命令在客户端中创建了一个证书:

New-SelfSignedCertificate -DnsName desasqlapps01.ad.impi.gob.mx -CertStoreLocation cert:\LocalMachine\My -KeySpec KeyExchange


 $CertPassword = ConvertTo-SecureString -String “PruebaCertificadoAutoFirma” -Force –AsPlainText
 Export-PfxCertificate -Cert cert:\LocalMachine\My\E7A3FCD624E6FBD74B1EB346F0A8E0CA38FA24A3 - 
 FilePath C:\testcerttramitemixto.pfx -Password $CertPassword

我创建了一个派生自UserNamePasswordValidator服务的类,服务配置的相关部分是:

    <system.web>
    <compilation debug="true" targetFramework="4.7.2" />
    <httpRuntime targetFramework="4.7.2" maxRequestLength="2147483647"/>
  </system.web>
  <system.serviceModel>
    <services>
      <service name="WS_TramiteMixto.IServiceTramiteMixto">

        <host>
          <baseAddresses>
            <add baseAddress ="http://desasqlapps01.ad.impi.gob.mx/" />
          </baseAddresses>
        </host>
        <endpoint address=""
                    binding="wsHttpBinding"
                    contract="WS_TramiteMixto.IServiceTramiteMixto"></endpoint>
        <!--<endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex" />-->

      </service>

    </services>
    <bindings>

      <!--<basicHttpBinding>

        <binding maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" receiveTimeout="00:30:00" sendTimeout="00:30:00">

          <readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="16384"/>
        </binding>
      </basicHttpBinding>-->

      <wsHttpBinding>
        <binding maxReceivedMessageSize="2147483647" receiveTimeout="00:30:00" sendTimeout="00:30:00">
          <security mode="Message">
            <message clientCredentialType="UserName" establishSecurityContext="true" />
          </security>
          <readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="16384"/>
        </binding>
      </wsHttpBinding>
      <webHttpBinding>
        <binding maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"/>
      </webHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceCredentials>


            <!--The serviceCredentials behavior allows one to
          specify a custom validator for username/password
          combinations.
          -->

            <userNameAuthentication userNamePasswordValidationMode="Custom"
                                    customUserNamePasswordValidatorType="WS_TramiteMixto.TramiteMixtoPaseValidator, WS_TramiteMixto" />


            <!--The serviceCredentials behavior allows one to define a service certificate. A service certificate is used by a client to authenticate the service and provide message protection. You must specify a server certificate when passing username/passwords to encrypt the information as it is sent on the wire. Otherwise the username and password information would be sent as clear text. This configuration references the "localhost" certificate installed during the setup instructions.
          -->

            <serviceCertificate findValue="desasqlapps01.ad.impi.gob.mx" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
          </serviceCredentials>
          <dataContractSerializer maxItemsInObjectGraph ="2147483647"/>
          <!-- Para evitar revelar información de los metadatos, establezca el valor siguiente en false antes de la implementación -->
          <serviceMetadata httpGetEnabled="True" policyVersion="Policy12" />
          <!-- Para recibir detalles de los errores de la excepción para la depuración, establezca el valor siguiente en true. Establézcalo en false antes de la implementación para evitar revelar información de la excepción -->
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <protocolMapping>
      <add binding="wsHttpBinding" scheme="http"/>
      <add binding="basicHttpsBinding" scheme="https" />
    </protocolMapping>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>

然后客户端配置如下:

<behaviors>
      <endpointBehaviors>
        <behavior name="webHttp">
          <webHttp />
        </behavior>
        <behavior name="ClientCertificateBehavior">
          <clientCredentials>
            <serviceCertificate>

           <!-- setting the certificatevalidationmode to peerorchaintrust means that if the certificate
            is in the user's trusted people store, then it will be trusted without performing a
            validation of the certificate's issuer chain. this setting is used here for convenience so that the
            sample can be run without having to have certificates issued by a certification authority (ca).
            this setting is less secure than the default, chaintrust. the security implications of this
            setting should be carefully considered before using peerorchaintrust in production code. -->

              <authentication certificateValidationMode="PeerOrChainTrust" />
            </serviceCertificate>
          </clientCredentials>
        </behavior>

      </endpointBehaviors>
<bindings>
    <wsHttpBinding>
            <binding name="WSHttpBinding_IService1" />
            <binding name="WSHttpBinding_IServiceTramiteMixto">
              <security mode="Message">
                <message clientCredentialType="UserName" establishSecurityContext="true" negotiateServiceCredential="true" />
              </security>
            </binding>
          </wsHttpBinding>
</bindings>
<endpoint address="http://desasqlapps01.ad.impi.gob.mx/WS_TramiteMIxto/ServiceTramiteMixto.svc"
  binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IServiceTramiteMixto"
  contract="ServicioTramiteMixto.IServiceTramiteMixto" name="WSHttpBinding_IServiceTramiteMixto">
      <!--<endpoint address="http://desasqlapps01.ad.impi.gob.mx/WS_TramiteMIxto/ServiceTramiteMixto.svc"
        binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IServiceTramiteMixto"
        contract="ServicioTramiteMixto.IServiceTramiteMixto" name="WSHttpBinding_IServiceTramiteMixto" behaviorConfiguration="ClientCertificateBehavior">-->
        <!--<identity>
          <dns value="http://desasqlapps01.ad.impi.gob.mx/"></dns>
        </identity>-->
        <identity>
          <certificate encodedValue="AwAAAAEAAAAUAAAAN9gRCkWxQeyqhRXP90pEMclVHZcgAAAAAQAAAFUDAAAwggNRMIICOaADAgECAhAo9Mgx1zrktUgP8eprE972MA0GCSqGSIb3DQEBBQUAMCcxJTAjBgNVBAMMHGRlc2FzcWxhcHBzMDEuYWQuaW1waS5nb2IubXgwHhcNMjAwMTAzMTkzOTAzWhcNMjEwMTAzMTk1OTAzWjAnMSUwIwYDVQQDDBxkZXNhc3FsYXBwczAxLmFkLmltcGkuZ29iLm14MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArYU9MV1Au0gmf043luz5ADknADdvOI+ufk52GP+q9pW7MpcCvyaZXd0OG7EeaeUMU9WriOX/TQrWrFQjqM06EXXzixEd7cF7qU2i0W3rpccrBQrhKollkoiOkkiQuXgHjqFFUMVlpeiCwRELjHGLeVnLTEnz9RzxKTUghtqHHkVECvkwuY6jVbUAUOY0+kEHPoSyPfYnIztSfWLd6mCDdMzRJ+vhSsCbzHFBQnWGwpQj5d58+XoLz9FPssmXjl/iPzZGmw+bPt7XT1y+OYNu7W0QsXYdcNJyzjjlwieiciEm7dPq4V3lQaIxkIlkRHRG6bHldYy9EI+esqZVJs4cvQIDAQABo3kwdzAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMCcGA1UdEQQgMB6CHGRlc2FzcWxhcHBzMDEuYWQuaW1waS5nb2IubXgwHQYDVR0OBBYEFC44LUubIpku7E8LvAxzOvSQkx83MA0GCSqGSIb3DQEBBQUAA4IBAQAxs4NLEVcpg8JIqThchTGYXripNyC5twZRn/SNsgVnNV5zSMzlPpwrDdpHwPbB5QNrm8XBfAIayWP0IjjB2LyMY33gIs1dNAM6xXffWNg3m6wOwMG/QomcZvWEfdUKGLG/AVwLQ61gR9NZO6I2xeRyLc7uRM8QYsu0vASjrUKjDNaBlGXxKLEJCcqC9ybQjaVas1ICY7n4rEP9PKr6Gmck2Pva6gVYJpguihhBeN1OYIsYPABP/qRoXmU9nt7jNKnJh9IxxaPt8yhR2kMlQOunbXoV6wVKSq484/9vikk3tTni7Yb44EiFoyyxscOq/Spzq+HsVm6hitQwk/cM2ID6" />
        </identity>
      </endpoint>

我已将证书放置在客户端的 Trusted People 存储区和服务器中当前用户的个人存储区中,但我得到了该异常,我无法调用服务中的任何方法。我还在服务中启用了跟踪,但没有记录任何内容,因此客户端似乎甚至无法访问该服务。

我已经读到这个错误可能是由 IIS 中的 LoadBalancing 引起的,我在其中将服务作为应用程序托管,根据这篇文章但微软声明要处理 IIS 中的负载平衡,你应该使用安全会话,从这里我' m 已经在服务绑定中做安全类型: <security mode="Message">

要求之一是对该服务的所有传入请求进行身份验证。

更新: 顺便说一句,读取的注释端点<endpoint address="http://desasqlapps01.ad.impi.gob.mx/WS_TramiteMIxto/ServiceTramiteMixto.svc" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IServiceTramiteMixto" contract="ServicioTramiteMixto.IServiceTramiteMixto" name="WSHttpBinding_IServiceTramiteMixto" behaviorConfiguration="ClientCertificateBehavior">是实际配置,注释是稍后添加的。

@Ross Bush 感谢您的回答我将服务中的 Web 配置编辑为如下所示:

         <wsHttpBinding>
        <binding maxReceivedMessageSize="2147483647" receiveTimeout="00:30:00" sendTimeout="00:30:00">
          <security mode="Transport">
<transport clientCredentialType="Certificate"/>
        <message clientCredentialType="UserName" />
        </security>
          <readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="16384"/>
        </binding>
      </wsHttpBinding>
      <webHttpBinding>
        <binding maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"/>
      </webHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <dataContractSerializer maxItemsInObjectGraph ="2147483647"/>
          <!-- Para evitar revelar información de los metadatos, establezca el valor siguiente en false antes de la implementación -->
          <serviceMetadata httpGetEnabled="True" policyVersion="Policy12" />
          <!-- Para recibir detalles de los errores de la excepción para la depuración, establezca el valor siguiente en true. Establézcalo en false antes de la implementación para evitar revelar información de la excepción -->
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <protocolMapping>
      <add binding="wsHttpBinding" scheme="http"/>

    </protocolMapping>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>

但是我不知道您建议的配置是否仅在 https 中有效:我知道收到一个运行时错误,指出

找不到与具有绑定 WSHttpBinding 的端点的方案 https 匹配的基地址。注册的基地址方案是http

并且该服务现在没有运行。

@Ross Bush 没关系,我已经解决了

<add binding="wsHttpBinding" scheme="https"/>

</protocolMapping>

到服务的配置

根据我收到的评论,我想重新提出我的问题,特别是我想知道-如果有人可以告诉我-

我的证书有效吗?是否可以在不使用 ssl 的情况下在 wcf 上设置用户名密码验证?

微软的教程只说:

您需要一个服务器证书,其主题名称包含机器的完全限定域名。必须更新服务器的配置文件以反映此新证书名称

但它没有说明使用 SSL 或 SSL 证书。预先感谢。

标签: c#wcfauthentication

解决方案


无需使用 HTTPS,就像您配置的一样。真的行。但是,无论使用 https 或配置服务证书,我们至少在服务器端指定一个证书。

<system.serviceModel>
    <services>
      <service name="WcfService3.Service1" behaviorConfiguration="mybehavior">
        <endpoint address="" binding="wsHttpBinding" bindingConfiguration="mybinding" contract="WcfService3.IService1"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
      </service>
    </services>
    <bindings>
      <wsHttpBinding>
        <binding name="mybinding">
          <security mode="Message">
            <message clientCredentialType="UserName"/>
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="mybehavior">
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
          <serviceCredentials>
            <serviceCertificate storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint" findValue="5ba5022f527e32ac02548fc5afc558de1d314cb6"/>
            <userNameAuthentication customUserNamePasswordValidatorType="WcfService3.CustUserNamePasswordVal,WcfService3" userNamePasswordValidationMode="Custom"/>
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

我不知道的是你的证书域名是否对应服务器机器名?我建议您通过添加服务引用来生成客户端代理类。
https://docs.microsoft.com/en-us/dotnet/framework/wcf/accessing-services-using-a-wcf-client
客户端生成的端点配置会自动添加一个 EndpointIdentity。

  <system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="WSHttpBinding_IService1">
          <security>
            <message clientCredentialType="UserName" />
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <client>
      <endpoint address="http://vabqia969vm:8818/Service1.svc" binding="wsHttpBinding"
        bindingConfiguration="WSHttpBinding_IService1" contract="ServiceReference1.IService1"
        name="WSHttpBinding_IService1">
        <identity>
          <certificate encodedValue="blablabla" />
<!--or,using dns to identity the server -->
          <!--<dns value="vabqia969vm"/>-->
        </identity>
      </endpoint>
    </client>

另外,请删除webhttpbinding相关配置。这与问题无关。
如果问题仍然存在,请随时告诉我。


推荐阅读