使用 wshttpbinding 的 WCF 用户名和密码验证不起作用

Posted

技术标签:

【中文标题】使用 wshttpbinding 的 WCF 用户名和密码验证不起作用【英文标题】:WCF UserName & Password validation using wshttpbinding notworking 【发布时间】:2019-09-15 13:35:39 【问题描述】:

我是 WCF 服务身份验证的新手,我试图使用 wshttpbinding 实现 wcfauthentication。但我得到了例外。

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

Web.Config:

<?xml version="1.0"?>
<configuration>
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5"/>
  </system.web>  
    <system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="wsHttp">
          <security mode="TransportWithMessageCredential">
            <message clientCredentialType="UserName"/>
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <services>
      <service name="WCFAuth.Service1" behaviorConfiguration="wsHttpBehavior">
        <endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttp" contract="WCFAuth.IService1">
          <identity>
            <dns value="localhost"/>
          </identity>
        </endpoint>
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:64765/"/>
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="wsHttpBehavior">
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="false"/>
          <serviceCredentials>
            <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WCFAuth.ServiceAuthanticator, WCFAuth"/>
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <!--
        To browse web app root directory during debugging, set the value below to true.
        Set to false before deployment to avoid disclosing web app folder information.
      -->
    <directoryBrowse enabled="true"/>
  </system.webServer>
</configuration>

服务认证类:

using System;
using System.Collections.Generic;
using System.IdentityModel.Selectors;
using System.Linq;
using System.ServiceModel;
using System.Web;

namespace WCFAuth

    public class ServiceAuthanticator : UserNamePasswordValidator
    

        public override void Validate(string userName, string password)
        
            string AppUserName = "ABC";
            string AppPwd = "abc";
            try
            
                if (userName.ToLower() != AppUserName.ToLower() && password != AppPwd)
                                        
                    throw new FaultException("Unknown Username or Incorrect Password");
                
            
            catch (Exception ex)
                                
                throw new FaultException("Unknown Username or Incorrect Password");
            
        
    

客户端配置文件:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <!--<binding name="base" />-->
              <binding name="base">
                <security mode="TransportCredentialOnly">
                  <transport clientCredentialType="Basic"/>
                </security>
              </binding>
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:64765/Service1.svc" binding="basicHttpBinding"
                bindingConfiguration="base" contract="WCFAuth.IService1" name="base" />
        </client>
    </system.serviceModel>
</configuration>

消费者:

class Program
    
        static void Main(string[] args)
        
            try
            
                WCFAuth.Service1Client client = new WCFAuth.Service1Client();                
                client.ClientCredentials.UserName.UserName = "test";
                client.ClientCredentials.UserName.Password = "test";                
                var temp = client.GetData(1);
                Console.WriteLine(temp);
            
            catch (Exception ex)
            
                Console.WriteLine(ex.Message);
            

            Console.ReadKey();
        
    

当我尝试浏览 svc 文件时出现附加异常。

谁能纠正我,我在哪里犯了错误,在此先感谢。

【问题讨论】:

【参考方案1】:

这里的问题是你使用了一个WSHttpBinding和Transport Security,但是你设置的基地址是http。此处无法使用 http,因为您通过网络发送凭据。

要么将其更改为 https,要么为开发目的创建第二个绑定配置。一个具有传输安全性 (https),​​另一个没有 (http)。

还要确保您的客户端绑定与来自您的服务器的绑定相匹配。

【讨论】:

谢谢你的建议,我得到了附加异常:System.ServiceModel.ServiceActivationException:由于编译期间出现异常,无法激活服务'/Service1.svc'。异常消息是:无法使用以下搜索条件找到 X.509 证书:StoreName 'My'、StoreLocation 'LocalMachine'、FindType 'FindByThumbprint'、FindValue '869f82bd848519ff8f35cbb6b667b34274c8dcfe'【参考方案2】:

正如 Marc 提到的,我们应该在托管服务时提供证书。在托管服务的过程中可能会出现问题。 这是一个参考配置,希望对你有用。

<system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="wsHttp">
          <security mode="TransportWithMessageCredential">
            <message clientCredentialType="UserName"/>
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <services>
      <service name="WCFAuth.Service1" behaviorConfiguration="wsHttpBehavior">
        <endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttp" contract="WCFAuth.IService1">
        </endpoint>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="wsHttpBehavior">
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="false"/>
          <serviceCredentials>
            <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WCFAuth.ServiceAuthanticator, WCFAuth"/>
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

然后我们应该在 IIS 站点绑定模块中添加一个 https 绑定。 服务地址为https://x.x.x.x:8865/Service1.svc 需要注意的一点是,我们通过添加服务引用来调用服务时,应该信任服务证书。

ServicePointManager.ServerCertificateValidationCallback += delegate
              
                  return true;
              ;
            ServiceReference2.Service1Client client = new ServiceReference2.Service1Client();
            client.ClientCredentials.UserName.UserName = "jack";
            client.ClientCredentials.UserName.Password = "123456";

此外,如果我们使用 SecurityMode.Message,我们应该在代码 sn-ps 中提供证书。

  <serviceCredentials>
            <serviceCertificate storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint" findValue="869f82bd848519ff8f35cbb6b667b34274c8dcfe"/>
            <userNameAuthentication customUserNamePasswordValidatorType="WcfService1.CustUserNamePasswordVal,WcfService1" userNamePasswordValidationMode="Custom"/>
          </serviceCredentials>

如果有什么我可以帮忙的,请随时告诉我。

【讨论】:

我收到附加异常:System.ServiceModel.ServiceActivationException:由于编译期间出现异常,无法激活服务“/Service1.svc”。异常消息是:无法使用以下搜索条件找到 X.509 证书:StoreName 'My'、StoreLocation 'LocalMachine'、FindType 'FindByThumbprint'、FindValue '869f82bd848519ff8f35cbb6b667b34274c8dcfe' 您提供的证书应该已安装在本地计算机证书存储中。我们可以使用 Certlm.msc 命令来检查已安装的证书。确保指纹为特定值的证书已安装在相应位置,或使用其他已安装的证书。

以上是关于使用 wshttpbinding 的 WCF 用户名和密码验证不起作用的主要内容,如果未能解决你的问题,请参考以下文章

尝试将 gSoap 与 WCF 和 WSHttpBinding 一起使用

WCF 默认绑定设置的文档(例如 wsHttpBinding)

使用 JSON 实现带有 WCF 服务 (wshttpBinding) 的 c# asp.net 应用程序

您可以使用 SOAP 和 WSHttpBinding 对 WCF 服务进行 jQuery 调用吗?

自定义 WCF 绑定等效于 WSHttpBinding 且 WS-Addressing 已关闭

netTcpBinding 或 wsHttpBinding