WCF支持多种认证技术,例如Windowns认证、X509证书、Issued Tokens、用户名密码认证等,在跨Windows域分布的系统中,用户名密码认证是比较常用的,要实现用户名密码认证,就必须需要X509证书,用来加密用户名和密码。
1. 创建数字证书
makecert -sr localmachine -ss My -n CN=ejiyuan -sky exchange -pe -r。
2. 创建服务代码
- [ServiceContract]
- public interface ICalculator
- {
- [OperationContract]
- double add(double x, double y);
- }
- public class CalculatorService : ICalculator
- {
- public double add(double x, double y)
- {
- return x + y;
- }
- }
- class Program
- {
- static void Main(string[] args)
- {
- ServiceHost _serviceHost = new ServiceHost(typeof(CalculatorService));
- _serviceHost.Opened += (s, q) =>
- {
- Console.WriteLine("服务已启动");
- Console.Read();
- };
- _serviceHost.Open();
- }
- }
3. 设置安全验证模式
- <bindings>
- <netTcpBinding>
- <binding name="nonSessionBinding">
- <!--当前绑定的安全认证模式-->
- <security mode="Message" >
- <!--定义消息级安全性要求的类型,为证书-->
- <message clientCredentialType="UserName" />
- </security>
- </binding>
- </netTcpBinding>
- </bindings>
4. 设置服务凭据值
- <behaviors>
- <serviceBehaviors >
- <behavior name="CalculatorServiceBehavior" >
- <serviceCredentials>
- <!--指定一个 X.509 证书,用户对认证中的用户名密码加密解密-->
- <serviceCertificate findValue="CN=ejiyuan" x509FindType="FindBySubjectDistinguishedName" storeLocation="LocalMachine" storeName="My"/>
- <clientCertificate>
- <!--自定义对客户端进行证书认证方式 这里为 None-->
- <authentication certificateValidationMode="None"/>
- </clientCertificate>
- <!--自定义用户名和密码验证的设置-->
- <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Wcf.Extensions.Security.UserNamePasswordValidator,Wcf.Extensions.Security" />
- </serviceCredentials>
- </behavior>
- </serviceBehaviors>
- </behaviors>
5. 自定义证书验证
通过继承自'System.IdentityModel.Selectors.UserNamePasswordValidator',然后我们重写里面的'Validate'方法来实现用户名密码认证逻辑
- public class UserNamePasswordValidator : System.IdentityModel.Selectors.UserNamePasswordValidator
- {
- public override void Validate(string userName, string password)
- {
- if (userName != "ejiyuan" || password != "123456")
- {
- throw new System.IdentityModel.Tokens.SecurityTokenException("Unknown Username or Password");
- }
- }
- }
6. 客户端代码
- class Program
- {
- static void Main(string[] args)
- {
- CalculatorClient client = new CalculatorClient();
- //指定认证的用户名和密码
- client.ClientCredentials.UserName.UserName = "ejiyuan";
- client.ClientCredentials.UserName.Password = "123456";
- var q = client.add(1, 2);
- Console.WriteLine(client.add(1,2));
- Console.Read();
- }
- }
7. 客户端配置信息(自动生成的)
- <system.serviceModel>
- <bindings>
- <netTcpBinding>
- <binding name="NetTcpBinding_ICalculator" >
- <security mode="Message">
- <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
- <message clientCredentialType="UserName" />
- </security>
- </binding>
- </netTcpBinding>
- </bindings>
- <client>
- <endpoint address="net.tcp://192.168.101.13:8000/calculatorservice"
- binding="netTcpBinding" bindingConfiguration="NetTcpBinding_ICalculator"
- contract="ServiceReference1.ICalculator" name="NetTcpBinding_ICalculator">
- <identity>
- <certificate encodedValue="AwAAAAEAAAAUAAAAgvtzbyRkxIGFn4UuyxD2+XJsJl8gAAAAAQAAAPQBAAAwggHwMIIBWaADAgECAhB/oj2gX287pUAmeLEVtWucMA0GCSqGSIb3DQEBBAUAMBIxEDAOBgNVBAMTB2VqaXl1YW4wHhcNMTAwNTI4MDkyNjQzWhcNMzkxMjMxMjM1OTU5WjASMRAwDgYDVQQDEwdlaml5dWFuMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCfOgnw6Vs7gS52Gsud0WsuFOoDeF4+4DL1HFIpQupdExtIkWwY2v2/t/pWHRRvPE/aPf3M6axUYaT4pQqPXBHQR1lb0Hi6XLUGkzsEk7tjiEMEkpt+/8rQIdtXlmmry7yDixoX8PKEd5cGAISjEdbVKJqjQnC55rQXeDYlIXoqlwIDAQABo0cwRTBDBgNVHQEEPDA6gBCTu+dYQbdaauBGEk3SjJ5FoRQwEjEQMA4GA1UEAxMHZWppeXVhboIQf6I9oF9vO6VAJnixFbVrnDANBgkqhkiG9w0BAQQFAAOBgQA1jOywoJ5Xh6B6W3Vw7xPa9A6AH0WtedXPd4YbCU465UdKeP5G2HtKLpS20MnkU6lIh22lxMnb3WGZh70l5Sg1Hl0j/SklLKtOXzeQnVLaPundd9RS1TD/hHwVyu+89cr0866etfGwI9IDpwjhj5ixT3VUHI3eGrXRj+IGx8/W8Q==" />
- </identity>
- </endpoint>
- </client>
- </system.serviceModel>