WCF 安全之自定义的用户名/密码身份验证
wcf name:user 
    pwd:pwd
 密码是死的
1. 服务器数字证书
(1) 安装证书管理中心(Certification Authority):控制面板——〉添加删除程序里安装
(2) 打开IIS,到默认站点(Default Web Site)——〉右键菜单,属性(Properties),打开属性管理窗口——〉(目录安全)Directory Security——〉Server Certificate,下一步一直到最后生成certreq.txt。
(3) 进入Certification Authority,右键根节点,选择All Tasks—Submit new question,选择生成的certreq.txt文件
(4) Click Pending requests, choose Request ID , 右键菜单所以任务---〉Issue。证书将出现在Issued Certificates,双击在detail中copy file生成证书
(5) 在IIS中安装证书
或者使用命令的方式准备证书:D:\>makecert -r -pe -n "CN=MyServer" -ss My -sky exchange2. 创建服务
 1 [ServiceContract]
    [ServiceContract]
2 public interface IService1
    public interface IService1
3 {
    {
4
5 [OperationContract]
        [OperationContract]
6 string Test();
        string Test();
7
8 [OperationContract]
        [OperationContract]
9 string GetUserName();
        string GetUserName();
10 }
    }
 [ServiceContract]
    [ServiceContract]2
 public interface IService1
    public interface IService13
 {
    {4

5
 [OperationContract]
        [OperationContract]6
 string Test();
        string Test();7

8
 [OperationContract]
        [OperationContract]9
 string GetUserName();
        string GetUserName();10
 }
    }
 1    public class Service1 : IService1
2 {
3 public string Test()
        public string Test()
4 {
        {
5 return "Server:" + DateTime.Now.ToString();
            return "Server:" + DateTime.Now.ToString();
6 }
        }
7
8 public string GetUserName()
        public string GetUserName()
9 {
        {
10 string userName = "";
            string userName = "";
11 if (ApplicationRequestContext.Current != null && ApplicationRequestContext.Current.AuthenticatedUsername != "")
            if (ApplicationRequestContext.Current != null && ApplicationRequestContext.Current.AuthenticatedUsername != "")
12 {
            {
13 userName = ApplicationRequestContext.Current.AuthenticatedUsername;
                userName = ApplicationRequestContext.Current.AuthenticatedUsername;
14 }
            }
15 else
            else
16 {
            {
17 string[] tokenParts = OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name.Split('|');
                string[] tokenParts = OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name.Split('|');
18 userName = tokenParts[0];
                userName = tokenParts[0];
19 }
            }
20
21 string str = "Hello " + userName + ".";
            string str = "Hello " + userName + ".";
22 //str += string.Format("  You entered: {0}", value);
            //str += string.Format("  You entered: {0}", value);
23 return str;// "hello world";
            return str;// "hello world";
24 }
        }
25 }
    }
2 {
3
 public string Test()
        public string Test()4
 {
        {5
 return "Server:" + DateTime.Now.ToString();
            return "Server:" + DateTime.Now.ToString();6
 }
        }7

8
 public string GetUserName()
        public string GetUserName()9
 {
        {10
 string userName = "";
            string userName = "";11
 if (ApplicationRequestContext.Current != null && ApplicationRequestContext.Current.AuthenticatedUsername != "")
            if (ApplicationRequestContext.Current != null && ApplicationRequestContext.Current.AuthenticatedUsername != "")12
 {
            {13
 userName = ApplicationRequestContext.Current.AuthenticatedUsername;
                userName = ApplicationRequestContext.Current.AuthenticatedUsername;14
 }
            }15
 else
            else16
 {
            {17
 string[] tokenParts = OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name.Split('|');
                string[] tokenParts = OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name.Split('|');18
 userName = tokenParts[0];
                userName = tokenParts[0];19
 }
            }20

21
 string str = "Hello " + userName + ".";
            string str = "Hello " + userName + ".";22
 //str += string.Format("  You entered: {0}", value);
            //str += string.Format("  You entered: {0}", value);23
 return str;// "hello world";
            return str;// "hello world";24
 }
        }25
 }
    }我们通过继承 UserNamePasswordValidator 来创建一个自定义验证器。
 1 public class MyUserNamePasswordValidator : UserNamePasswordValidator
public class MyUserNamePasswordValidator : UserNamePasswordValidator
2 {
{
3 public override void Validate(string userName, string password)
  public override void Validate(string userName, string password)
4 {
  {
5 if (userName != "user" || password != "pwd")
    if (userName != "user" || password != "pwd")
6 {
    {
7 throw new SecurityTokenException("Unknown Username or Password");
      throw new SecurityTokenException("Unknown Username or Password");
8 }
    }
9 }
  }
10 }
}
11
接下来创建服务器配置文件,我们使用 WsHttpBinding,采取 TransportWithMessageCredential安全模式。其他的设置还包括 certificateValidationMode、userNamePasswordValidationMode、customUserNamePasswordValidatorType 等。 public class MyUserNamePasswordValidator : UserNamePasswordValidator
public class MyUserNamePasswordValidator : UserNamePasswordValidator2
 {
{3
 public override void Validate(string userName, string password)
  public override void Validate(string userName, string password)4
 {
  {5
 if (userName != "user" || password != "pwd")
    if (userName != "user" || password != "pwd")6
 {
    {7
 throw new SecurityTokenException("Unknown Username or Password");
      throw new SecurityTokenException("Unknown Username or Password");8
 }
    }9
 }
  }10
 }
}11

 1
2 <system.serviceModel>
    <system.serviceModel>
3
4 <services>
        <services>
5 <service name="WcfServiceUserName.Service1" behaviorConfiguration="NewBehavior">
            <service name="WcfServiceUserName.Service1" behaviorConfiguration="NewBehavior">
6 <!-- Service Endpoints -->
                <!-- Service Endpoints -->
7
8 <endpoint address="https://servername/WCFUserName/Service1.svc/ws1" binding="wsHttpBinding" bindingConfiguration="Binding1" contract="WcfServiceUserName.IService1">
                <endpoint address="https://servername/WCFUserName/Service1.svc/ws1" binding="wsHttpBinding" bindingConfiguration="Binding1" contract="WcfServiceUserName.IService1">
9 <identity>
                    <identity>
10 <dns value="servername(要和证书中申请的一样)"/>
                        <dns value="servername(要和证书中申请的一样)"/>
11 </identity>
                    </identity>
12 </endpoint>
                </endpoint>
13 <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
                <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
14 </service>
            </service>
15 </services>
        </services>
16 <bindings>
        <bindings>
17 <wsHttpBinding>
            <wsHttpBinding>
18 <binding name="Binding1">
                <binding name="Binding1">
19 <security mode="TransportWithMessageCredential">
                    <security mode="TransportWithMessageCredential">
20 <message clientCredentialType="UserName"/>
            <message clientCredentialType="UserName"/>
21 </security>
                    </security>
22 </binding>
                </binding>
23 </wsHttpBinding>
            </wsHttpBinding>
24 </bindings>
        </bindings>
25 <behaviors>
        <behaviors>
26 <serviceBehaviors>
            <serviceBehaviors>
27 <behavior name="NewBehavior">
                <behavior name="NewBehavior">
28 <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
                    <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
29 <serviceMetadata httpGetEnabled="true"/>
                    <serviceMetadata httpGetEnabled="true"/>
30 <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
                    <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
31 <serviceDebug includeExceptionDetailInFaults="true"/>
                    <serviceDebug includeExceptionDetailInFaults="true"/>
32 <serviceCredentials>
                    <serviceCredentials>
33 <clientCertificate>
                        <clientCertificate>
34 <authentication certificateValidationMode="None"/>
                            <authentication certificateValidationMode="None"/>
35 </clientCertificate>
                        </clientCertificate>
36 <!--userNamePasswordValidationMode can not equal Window,must be Custom-->
            <!--userNamePasswordValidationMode can not equal Window,must be Custom-->
37 <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="CustomUserNamePasswordValidator(类的名称),程序集名称"/>
            <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="CustomUserNamePasswordValidator(类的名称),程序集名称"/>
38 </serviceCredentials>
                    </serviceCredentials>
39 </behavior>
                </behavior>
40 </serviceBehaviors>
            </serviceBehaviors>
41 </behaviors>
        </behaviors>
42 </system.serviceModel>
  </system.serviceModel>

2
 <system.serviceModel>
    <system.serviceModel>3

4
 <services>
        <services>5
 <service name="WcfServiceUserName.Service1" behaviorConfiguration="NewBehavior">
            <service name="WcfServiceUserName.Service1" behaviorConfiguration="NewBehavior">6
 <!-- Service Endpoints -->
                <!-- Service Endpoints -->7

8
 <endpoint address="https://servername/WCFUserName/Service1.svc/ws1" binding="wsHttpBinding" bindingConfiguration="Binding1" contract="WcfServiceUserName.IService1">
                <endpoint address="https://servername/WCFUserName/Service1.svc/ws1" binding="wsHttpBinding" bindingConfiguration="Binding1" contract="WcfServiceUserName.IService1">9
 <identity>
                    <identity>10
 <dns value="servername(要和证书中申请的一样)"/>
                        <dns value="servername(要和证书中申请的一样)"/>11
 </identity>
                    </identity>12
 </endpoint>
                </endpoint>13
 <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
                <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>14
 </service>
            </service>15
 </services>
        </services>16
 <bindings>
        <bindings>17
 <wsHttpBinding>
            <wsHttpBinding>18
 <binding name="Binding1">
                <binding name="Binding1">19
 <security mode="TransportWithMessageCredential">
                    <security mode="TransportWithMessageCredential">20
 <message clientCredentialType="UserName"/>
            <message clientCredentialType="UserName"/>21
 </security>
                    </security>22
 </binding>
                </binding>23
 </wsHttpBinding>
            </wsHttpBinding>24
 </bindings>
        </bindings>25
 <behaviors>
        <behaviors>26
 <serviceBehaviors>
            <serviceBehaviors>27
 <behavior name="NewBehavior">
                <behavior name="NewBehavior">28
 <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
                    <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->29
 <serviceMetadata httpGetEnabled="true"/>
                    <serviceMetadata httpGetEnabled="true"/>30
 <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
                    <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->31
 <serviceDebug includeExceptionDetailInFaults="true"/>
                    <serviceDebug includeExceptionDetailInFaults="true"/>32
 <serviceCredentials>
                    <serviceCredentials>33
 <clientCertificate>
                        <clientCertificate>34
 <authentication certificateValidationMode="None"/>
                            <authentication certificateValidationMode="None"/>35
 </clientCertificate>
                        </clientCertificate>36
 <!--userNamePasswordValidationMode can not equal Window,must be Custom-->
            <!--userNamePasswordValidationMode can not equal Window,must be Custom-->37
 <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="CustomUserNamePasswordValidator(类的名称),程序集名称"/>
            <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="CustomUserNamePasswordValidator(类的名称),程序集名称"/>38
 </serviceCredentials>
                    </serviceCredentials>39
 </behavior>
                </behavior>40
 </serviceBehaviors>
            </serviceBehaviors>41
 </behaviors>
        </behaviors>42
 </system.serviceModel>
  </system.serviceModel>3. 创建客户端
启动服务器后,创建客户端代理文件。注意自动生成的客户端配置文件中包含了服务器数字证书的相关信息。
 1 <system.serviceModel>
    <system.serviceModel>
2 <bindings>
        <bindings>
3 <wsHttpBinding>
            <wsHttpBinding>
4 <binding name="WSHttpBinding_IService1" closeTimeout="00:01:00"
                <binding name="WSHttpBinding_IService1" closeTimeout="00:01:00"
5 openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
6 bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
                    bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
7 maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                    maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
8 messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
                    messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
9 allowCookies="false">
                    allowCookies="false">
10 <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
11 maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
12 <reliableSession ordered="true" inactivityTimeout="00:10:00"
                    <reliableSession ordered="true" inactivityTimeout="00:10:00"
13 enabled="false" />
                        enabled="false" />
14 <security mode="TransportWithMessageCredential">
                    <security mode="TransportWithMessageCredential">
15 <transport clientCredentialType="None" proxyCredentialType="None"
                        <transport clientCredentialType="None" proxyCredentialType="None"
16 realm="" />
                            realm="" />
17 <message clientCredentialType="UserName" negotiateServiceCredential="true"
                        <message clientCredentialType="UserName" negotiateServiceCredential="true"
18 algorithmSuite="Default" establishSecurityContext="true" />
                            algorithmSuite="Default" establishSecurityContext="true" />
19 </security>
                    </security>
20 </binding>
                </binding>
21 </wsHttpBinding>
            </wsHttpBinding>
22 </bindings>
        </bindings>
23 <client>
        <client>
24 <endpoint address="https://servername/WCFUserName/Service1.svc/ws1"
            <endpoint address="https://servername/WCFUserName/Service1.svc/ws1"
25 binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IService1"
                binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IService1"
26 contract="IService1" name="WSHttpBinding_IService1">
                contract="IService1" name="WSHttpBinding_IService1">
27 <identity>
                <identity>
28 <dns value="servername" />
                    <dns value="servername" />
29 </identity>
                </identity>
30 </endpoint>
            </endpoint>
31 </client>
        </client>
32 </system.serviceModel>
    </system.serviceModel>
 <system.serviceModel>
    <system.serviceModel>2
 <bindings>
        <bindings>3
 <wsHttpBinding>
            <wsHttpBinding>4
 <binding name="WSHttpBinding_IService1" closeTimeout="00:01:00"
                <binding name="WSHttpBinding_IService1" closeTimeout="00:01:00"5
 openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"6
 bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
                    bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"7
 maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                    maxBufferPoolSize="524288" maxReceivedMessageSize="65536"8
 messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
                    messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"9
 allowCookies="false">
                    allowCookies="false">10
 <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"11
 maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />12
 <reliableSession ordered="true" inactivityTimeout="00:10:00"
                    <reliableSession ordered="true" inactivityTimeout="00:10:00"13
 enabled="false" />
                        enabled="false" />14
 <security mode="TransportWithMessageCredential">
                    <security mode="TransportWithMessageCredential">15
 <transport clientCredentialType="None" proxyCredentialType="None"
                        <transport clientCredentialType="None" proxyCredentialType="None"16
 realm="" />
                            realm="" />17
 <message clientCredentialType="UserName" negotiateServiceCredential="true"
                        <message clientCredentialType="UserName" negotiateServiceCredential="true"18
 algorithmSuite="Default" establishSecurityContext="true" />
                            algorithmSuite="Default" establishSecurityContext="true" />19
 </security>
                    </security>20
 </binding>
                </binding>21
 </wsHttpBinding>
            </wsHttpBinding>22
 </bindings>
        </bindings>23
 <client>
        <client>24
 <endpoint address="https://servername/WCFUserName/Service1.svc/ws1"
            <endpoint address="https://servername/WCFUserName/Service1.svc/ws1"25
 binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IService1"
                binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IService1"26
 contract="IService1" name="WSHttpBinding_IService1">
                contract="IService1" name="WSHttpBinding_IService1">27
 <identity>
                <identity>28
 <dns value="servername" />
                    <dns value="servername" />29
 </identity>
                </identity>30
 </endpoint>
            </endpoint>31
 </client>
        </client>32
 </system.serviceModel>
    </system.serviceModel>开始调用服务,注意将 CertificateValidationMode 设置为 None,当然也可以写到配置文件中。
 1 try
            try
2 {
            {
3 WSHttpBinding mybinding = new WSHttpBinding();
                WSHttpBinding mybinding = new WSHttpBinding();
4 mybinding.Security.Mode = SecurityMode.TransportWithMessageCredential;
                mybinding.Security.Mode = SecurityMode.TransportWithMessageCredential;
5 mybinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
                mybinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
6
7 EndpointAddress ea = new EndpointAddress(new Uri("https://servername/WCFUserName/Service1.svc/ws1"));
                EndpointAddress ea = new EndpointAddress(new Uri("https://servername/WCFUserName/Service1.svc/ws1"));
8 Service1Client client = new Service1Client(mybinding, ea);
                Service1Client client = new Service1Client(mybinding, ea);
9
10 client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None;
                client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None;
11 client.ClientCredentials.UserName.UserName = "user";
                client.ClientCredentials.UserName.UserName = "user";
12 client.ClientCredentials.UserName.Password = "pwd";
                client.ClientCredentials.UserName.Password = "pwd";
13 client.Open();
                client.Open();
14 MessageBox.Show(client.GetUserName());
                MessageBox.Show(client.GetUserName());
15 }
            }
16 catch (SecurityTokenException ex)
            catch (SecurityTokenException ex)
17 {
            {
18 MessageBox.Show(ex.Message.ToString());
                MessageBox.Show(ex.Message.ToString());
19 }
            }
20 
          
 try
            try2
 {
            {3
 WSHttpBinding mybinding = new WSHttpBinding();
                WSHttpBinding mybinding = new WSHttpBinding();4
 mybinding.Security.Mode = SecurityMode.TransportWithMessageCredential;
                mybinding.Security.Mode = SecurityMode.TransportWithMessageCredential;5
 mybinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
                mybinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;6

7
 EndpointAddress ea = new EndpointAddress(new Uri("https://servername/WCFUserName/Service1.svc/ws1"));
                EndpointAddress ea = new EndpointAddress(new Uri("https://servername/WCFUserName/Service1.svc/ws1"));8
 Service1Client client = new Service1Client(mybinding, ea);
                Service1Client client = new Service1Client(mybinding, ea);9

10
 client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None;
                client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None;11
 client.ClientCredentials.UserName.UserName = "user";
                client.ClientCredentials.UserName.UserName = "user";12
 client.ClientCredentials.UserName.Password = "pwd";
                client.ClientCredentials.UserName.Password = "pwd";13
 client.Open();
                client.Open();14
 MessageBox.Show(client.GetUserName());
                MessageBox.Show(client.GetUserName());15
 }
            }16
 catch (SecurityTokenException ex)
            catch (SecurityTokenException ex)17
 {
            {18
 MessageBox.Show(ex.Message.ToString());
                MessageBox.Show(ex.Message.ToString());19
 }
            }20
 
           
                    
                     
                    
                 
                    
                
 
    
 
         
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号