65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 SSL 构建 WCF 身份验证自托管应用程序

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.67/5 (2投票s)

2013年8月25日

CPOL

2分钟阅读

viewsIcon

20869

构建一个使用 SSL 的基于用户名身份验证的 WCF 自托管应用程序

引言

这是一个向导,引导您完成基于 wsHttpBinding 且无需证书的 WCF 服务和客户端构建。

背景

我开始研究使用用户名进行 WCF 身份验证。因此,我发现了 basicHttpBindingwsHttpBinding。 在本技巧中,我将向您展示如何使用 wsHttpBinding 和 SSL 与身份验证的 WCF 服务应用程序进行通信。

您可能已经知道如何构建 WCF 应用程序。因此,本页不介绍如何构建 WCF 应用程序,而是介绍如何构建自定义用户名验证器以及如何构建配置文件。

Using the Code

该应用程序有两个部分,一个是服务部分,另一个是客户端部分。

在服务器部分,您可以构建一个名为 CustomUserNameValidator 的类并继承 UserNamePasswordValidator。 并实现 abstract 方法 "Validate"。 当用户名和密码无效时,您可以抛出一些异常。

服务工作

  • 您应该完成验证器代码。
  • 您应该为传输加密制作证书,可以按照 文章进行操作。
  • 您应该为 SSL 证书制作证书,可以按照 文章进行操作。
  • 将您的服务应用程序绑定到 SSL。
  • 完成您的服务配置。

验证器代码

public class CustomUserNameValidator : UserNamePasswordValidator
    {
        private const string USERNAME_ELEMENT_NAME = "userName";

        private const string PASSWORD_ELEMENT_NAME = "password";

        private const string FAULT_EXCEPTION_MESSAGE = "UserName or Password is incorrect!";

        public override void Validate(string userName, string password)
        {
            Guarder.Guard.ArgumentNotNull(userName)
                .ArgumentNotNull(password);
            var validateUserName = ConfigurationManager.AppSettings[USERNAME_ELEMENT_NAME];
            var validatePassword = ConfigurationManager.AppSettings[PASSWORD_ELEMENT_NAME];
            var validateCondition = userName.Equals(validateUserName) && password.Equals(validatePassword);
            if (!validateCondition)
            {
                throw new FaultException(FAULT_EXCEPTION_MESSAGE);
            }
        }
    } 

制作您的传输加密证书

makecert.exe -sr LocalMachine -ss My -a sha1 -n CN=ServerCert -sky exchange –pe 

将您的应用程序绑定到 SSL 代码

netsh http add sslcert ipport=0.0.0.0:12221 certhash=32e636c3cefb16726b88b082b22b51194d77f865 
appid={ba77e2bd-7499-44ee-bfb0-b45188f94e7f} clientcertnegotiation=enable 

在代码中,certhash 是证书的指纹,您可以在 Windows 的原生工具 mms 应用程序中获取它。 appid,您可以从项目的程序集信息中获取。

以及服务配置

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
  <appSettings>
    <add key="username" value="your username"/>
    <add key="password" value="your password"/>
  </appSettings>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="securityBehavior">
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
          <serviceCredentials>
            <!--makecert.exe -sr CurrentUser -ss My -a sha1 -n CN=ServerCert -sky exchange –pe-->
            <serviceCertificate
              findValue="ServerCert"
              x509FindType="FindBySubjectName"
              storeLocation="CurrentUser"
              storeName="My"/>
            <userNameAuthentication
              userNamePasswordValidationMode="Custom"
              customUserNamePasswordValidatorType=
              "TimeSynchronizeHttpsServer.CustomUserNameValidator,TimeSynchronizeHttpsServer"/>
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <wsHttpBinding>
        <binding name="securityMessageBinding">
          <security mode="TransportWithMessageCredential">
            <transport clientCredentialType="Basic"/>
            <message clientCredentialType="UserName"/>
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <services>
      <service name="TimeSynchronizeHttpsServer.TimeSynchronizeService" 
      behaviorConfiguration="securityBehavior">
        <!--to use https should bind ssl to url follow 
        http://www.run-corp.com/how-to-configure-self-hosted-wcf-server-endpoint/ 
        and use a difference cert with your service certificate.-->
        <!--When you bind certificate to ssl url there is a parameter named appid, 
        it is the server guid of assembly info-->
        <endpoint address="https://127.0.0.1:12221/TimeSynchronize"
                  binding="wsHttpBinding"  
                  bindingConfiguration="securityMessageBinding"
                  contract="TimeSynchronizeHttpsServer.ITimeSynchronizeService">
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" 
        contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="https://:8733/Design_Time_Addresses/
            TimeSynchonizeHttpsServer/TimeSynchronizeService/" />
          </baseAddresses>
        </host>
      </service>
    </services>
  </system.serviceModel>
</configuration>   

客户端工作

  • 完成客户端配置
  • 完成客户端自定义验证器
  • 完成客户端代码

完成客户端配置

客户端配置如下所示

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
  <appSettings>
    <add key="username" value="your username"/>
    <add key="password" value="your password"/>
  </appSettings>
  <system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="securityMixedBinding">
          <security mode="TransportWithMessageCredential">
            <transport clientCredentialType="Basic"/>
            <message clientCredentialType="UserName"/>
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <client>
      <endpoint address="https://127.0.0.1:12221/TimeSynchronize"
                binding="wsHttpBinding" bindingConfiguration="securityMixedBinding"
                contract="ITimeSynchronizeService" 
                name="DefaultBinding_ITimeSynchronizeService_ITimeSynchronizeService" />
    </client>
  </system.serviceModel>
</configuration> 

客户端自定义验证器

class CertificateValidator
    {
        public static void SetCertificatePolicy ( )
        {
            ServicePointManager.ServerCertificateValidationCallback
                       += RemoteCertificateValidate;
        }
        private static bool RemoteCertificateValidate 
        ( object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors error )
        {
            System.Console.WriteLine ( "Warning, trust any certificate" );
            return true;
        }
    } 

验证器的用途是确保远程证书有效。 由于证书由我们自己发布,因此我们应该欺骗服务器通过验证。 并且我们应该在调用契约之前调用 "SetCertificatePolicy" 方法。

客户端应用程序代码

class Program
    {
        private const string USERNAME = "userName";
        private const string PASSWORD = "password";
        static void Main ( string[] args )
        {
            var proxy = new TimeSynchronizeServiceClient ( );
            var userName = ConfigurationManager.AppSettings[USERNAME];
            var password = ConfigurationManager.AppSettings[PASSWORD];
            proxy.ClientCredentials.UserName.UserName = userName;
            proxy.ClientCredentials.UserName.Password = password;
            CertificateValidator.SetCertificatePolicy ( );
            var time = proxy.GetTime ( );
            var builder = new StringBuilder ( );
            builder.Append ( "Server time is:" ).Append ( " " ).Append ( time );
            var message = builder.ToString ( );
            Console.WriteLine ( message );
            Console.ReadKey ( );
        }
    } 

结果

我在互联网上搜索了大量文档,并自行修改了一些演示。 此文档在我运行应用程序时可以正常工作。 希望此页面对您有所帮助。

© . All rights reserved.