使用 SSL 构建 WCF 身份验证自托管应用程序
构建一个使用 SSL 的基于用户名身份验证的 WCF 自托管应用程序
引言
这是一个向导,引导您完成基于 wsHttpBinding
且无需证书的 WCF 服务和客户端构建。
背景
我开始研究使用用户名进行 WCF 身份验证。因此,我发现了 basicHttpBinding
和 wsHttpBinding
。 在本技巧中,我将向您展示如何使用 wsHttpBinding
和 SSL 与身份验证的 WCF 服务应用程序进行通信。
您可能已经知道如何构建 WCF 应用程序。因此,本页不介绍如何构建 WCF 应用程序,而是介绍如何构建自定义用户名验证器以及如何构建配置文件。
Using the Code
该应用程序有两个部分,一个是服务部分,另一个是客户端部分。
在服务器部分,您可以构建一个名为 CustomUserNameValidator
的类并继承 UserNamePasswordValidator
。 并实现 abstract
方法 "Validate
"。 当用户名和密码无效时,您可以抛出一些异常。
服务工作
验证器代码
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 ( );
}
}
结果
我在互联网上搜索了大量文档,并自行修改了一些演示。 此文档在我运行应用程序时可以正常工作。 希望此页面对您有所帮助。