证书
以管理员身份打开VS开发人员命令提示符工具
然后输入如下字符串
makecert -sr localmachine -ssRoot -n CN=GreenWhale -sky exchange -pe -r。
回车返回Success即可。
然后打开“C:\Windows\System32\en-US\certlm.msc” Zh-CN也可 “C:\Windows\System32\zh-CN\certlm.msc”
别打错了不是这个“certmgr.msc”
然后就可以看到证书了,导出证书,软件发布后让客户端安装此证书即可。
服务端
服务端回调接口:
using
System.ServiceModel;
using
System.Net;
namespace
WcfService1
{
publicinterface
IServerCallClient
{
[OperationContract]
IPEndPointServerRequestClientIP();
[OperationContract]
voidServerSayMsg(string
text);
}
}
服务接口
using System;
using System.ServiceModel;
namespace WcfService1
{
[ServiceContract(CallbackContract=typeof(IServerCallClient))]
publicinterface
IClientCallServer
{
[OperationContract]
voidClientSayToServer(string
text);
[OperationContract]
DateTimeClientRequestDateTime();
}
}
WCF 服务端代码实现
请注意,服务端回调客户端时 客户端的链接必须没有断开,断开了就无法回调了,
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using System.Timers;
namespace WcfService1
{
// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码、svc 和配置文件中的类名“Service1”。
// 注意: 为了启动 WCF 测试客户端以测试此服务,请在解决方案资源管理器中选择 Service1.svc 或 Service1.svc.cs,然后开始调试。
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
publicclass
ClientCallServer :IClientCallServer,IDisposable
{
Timer timer=
newTimer();
publicClientCallServer()
{
timer.Elapsed+=
Timer_Elapsed;
timer.Interval=
5000;
timer.Start();
}
privatevoid
Timer_Elapsed(object sender,ElapsedEventArgs e)
{
if (ServerCallClient!=
null)
{
foreach (var itemin
ServerCallClient)
{
item.ServerSayMsg("SB");
}
}
}
publicstatic
List<IServerCallClient> ServerCallClient=
newList<IServerCallClient>();
publicDateTime
ClientRequestDateTime()
{
returnDateTime.Now;
}
publicvoid
ClientSayToServer(string text)
{
var channel=
OperationContext.Current.GetCallbackChannel<IServerCallClient>();
ServerCallClient.Add(channel);
Debug.WriteLine(OperationContext.Current.SessionId);
Debug.WriteLine(text);
}
publicvoid
Dispose()
{
ServerCallClient.Clear();
}
}
}
身份认证
实现身份认证需要服务端继承System.IdentityModel.Selectors.UserNamePasswordValidator类。同理需要引用System.IdentityModel.Dll;
namespace WcfService1
{
/// <summary>
/// WCF身份认证
/// </summary>
publicclass
WCFValidator :
System.IdentityModel.Selectors.UserNamePasswordValidator
{
///
<summary>
/// 身份及密码验证
///
</summary>
///
<param name="userName"></param>
///
<param name="password"></param>
publicoverride
void
Validate(string userName,string password)
{
if (userName==
"1234"&&
password==
"1234")//身份验证不过则报错,过了就过了。
{
}
else
{
thrownew
System.IdentityModel.Tokens.SecurityTokenException("Unknown
Username or Password");
}
}
}
}
Web配置文件
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<compilationdebug="true"targetFramework="4.0"/>
</system.web>
<system.serviceModel>
<services>
<servicename="WcfService1.ClientCallServer">
<endpointaddress=""binding="wsDualHttpBinding"bindingConfiguration="NewBinding0"
contract="WcfService1.IClientCallServer">
</endpoint>
</service>
</services>
<bindings>
<wsDualHttpBinding>
<bindingname="NewBinding0">
<securitymode="Message"><--消息加密->
<messageclientCredentialType="UserName"/>
</security>
</binding>
</wsDualHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceCredentials>
<--findValue
公司名称=GreenWhale,storeLocation==存储位置本机,储存位置:Root(根证书区)->
<serviceCertificatefindValue="CN=GreenWhale"x509FindType="FindBySubjectDistinguishedName"storeLocation="LocalMachine"storeName="Root"></serviceCertificate>
<clientCertificate>
<authenticationcertificateValidationMode="None"></authentication>
</clientCertificate>
<---customUserNamePasswordValidatorType,先放动态库的命名空间+类名,然后时逗号然后是dll名称,我这里时WcfService1--->
<userNameAuthenticationuserNamePasswordValidationMode="Custom"includeWindowsGroups="false"customUserNamePasswordValidatorType="WcfService1.WCFValidator,WcfService1"></userNameAuthentication>
</serviceCredentials>
<!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false -->
<serviceMetadatahttpGetEnabled="true"/>
<!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息 -->
<serviceDebugincludeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironmentaspNetCompatibilityEnabled="false"
multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<system.webServer>
<modulesrunAllManagedModulesForAllRequests="true"/>
<!--
若要在调试过程中浏览 Web 应用程序根目录,请将下面的值设置为 True。
在部署之前将该值设置为 False 可避免泄露 Web 应用程序文件夹信息。
-->
<directoryBrowseenabled="true"/>
</system.webServer>
</configuration>
客户端
客户端很简单,首先引用WCF服务,然后在连接时输入对应的账号和密码即可。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.ServiceModel;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using WindowsFormsApp1.Service;
namespace WindowsFormsApp1
{
publicpartial
class
Form1 :Form,
IClientCallServerCallback
{
publicForm1()
{
InitializeComponent();
context=
newInstanceContext(this);
client=
newClientCallServerClient(context);
}
publicIPEndPoint
ServerRequestClientIP()
{
thrownew
NotImplementedException();
}
InstanceContext context;
publicvoid
ServerSayMsg(string text)
{
MessageBox.Show(text);
}
ClientCallServerClient client;
privatevoid
button1_Click(object sender,EventArgs e)
{
// certificateValidationMode
client.ClientCredentials.UserName.UserName=
"1234";
client.ClientCredentials.UserName.Password=
"1234";
client.ClientSayToServer("Fuck");
}
}
}