WCF基于用户名和密码安全成功测试

目标:
1.客户端与服务器端通信使用x509证书验证,但不用客户端安装证书。只需要服务器端配置好证书即可。
2.验证使用用户名密码形式。

操作:
(这里的测试使用wcf项目模板缺省的服务,即只要新建一个使用vs2008自动生成的wcf项目就行了,

它会自动生成有一个GetData方法,我就用这个方法进行测试)
1.新建WCF服务应用程序.

1.1生成一个服务器证书:运行Visual Studio 2008 命令提示工具:

输入:makecert -r -pe -n "CN=MyServer" -sr LocalMachine -ss My -sky exchange执行。

-sr LocalMachine 请一定保存到LodcalMachine中.目的就是到时如果你部署这个wcf服务的时候可以让IIS找到证书,

反之,IIS会报找不到x509证书.

2.配置web.config文件:
这里要注意的是把storeLocation设为LocalMachine,原因也是到时需要部署的时候可以免掉很多麻烦,因为以后发布到iis时很可以不能正常验证到证书的私钥.

 1:  <system.serviceModel>
 2:      <bindings>
 3:        <wsHttpBinding>
 4:          <binding name="NewBinding0">
 5:            <security>
 6:              <message clientCredentialType="UserName" />
 7:            </security>
 8:          </binding>
 9:        </wsHttpBinding>
10:      </bindings>
11:      <services>
12:        <service behaviorConfiguration="WcfService2.Service1Behavior"
13:          name="WcfService2.Service1">
14:          <endpoint address="" binding="wsHttpBinding" bindingConfiguration="NewBinding0"
15:            contract="WcfService2.IService1">
16:          </endpoint>
17:          <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
18:        </service>
19:      </services>
20:      <behaviors>
21:        <serviceBehaviors>
22:          <behavior name="WcfService2.Service1Behavior">
23:            <serviceMetadata httpGetEnabled="true" />
24:            <serviceDebug includeExceptionDetailInFaults="false" />
25:            <serviceCredentials>
26:              <clientCertificate>
27:                <authentication certificateValidationMode="None" />
28:              </clientCertificate>
29:              <serviceCertificate findValue="MyServer" storeLocation="LocalMachine" x509FindType="FindBySubjectName" />
30:              <userNameAuthentication userNamePasswordValidationMode="Custom"
31:                customUserNamePasswordValidatorType="WcfService2.MyUserNamePasswordValidator,WcfService2" />
32:            </serviceCredentials>
33:          </behavior>
34:        </serviceBehaviors>
35:      </behaviors>
36:    </system.serviceModel>

3.建造验证客户端用户名和密码的方法.

这里注意的是必须与web.config文件中的customUserNamePasswordValidatorType=中的内容一致,

格式是:"命名空间.方法名,命名空间"

实际项目应用中这里应该是从数据库里确认用客是否合法。

 1:  namespace WcfService2 
 2:  { 
 3:      public class MyUserNamePasswordValidator : UserNamePasswordValidator 
 4:      { 
 5:          public override void Validate(string userName, string password) 
 6:          { 
 7:              if (userName != "jac" || password != "jac") 
 8:              { 
 9:                  throw new SecurityTokenException("Unknown Username or Password"); 
10:              } 
11:          } 
12:      } 
13:  }

至此,wcf服务配置完成。

4.新建一个asp.net项目,并添加服务引用这个wcf服务.

5.修改asp.net项目的web.config文件(一定要在引用wcf服务后).

添加一个endpointBehaviors:

 1:  <behaviors>
 2:    <endpointBehaviors>
 3:      <behavior name="jacBehavior">
 4:        <clientCredentials>
 5:          <serviceCertificate>
 6:            <authentication certificateValidationMode="None" />
 7:          </serviceCertificate>
 8:        </clientCredentials>
 9:      </behavior>
10:    </endpointBehaviors>
11:  </behaviors>

然后让它生效,

1:  <endpoint address="http://j-8de9be98d1184/Service1.svc" behaviorConfiguration="jacBehavior"
2:   binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IService1"
3:   contract="ServiceReference1.IService1" name="WSHttpBinding_IService1">

以下是完整的asp.net客户端的web.config文件的system.serviceModel部份

 1:  <system.serviceModel>
 2:    <behaviors>
 3:      <endpointBehaviors>
 4:        <behavior name="jacBehavior">
 5:          <clientCredentials>
 6:            <serviceCertificate>
 7:              <authentication certificateValidationMode="None" />
 8:            </serviceCertificate>
 9:          </clientCredentials>
10:        </behavior>
11:      </endpointBehaviors>
12:    </behaviors>
13:    <bindings>
14:      <wsHttpBinding>
15:        <binding name="WSHttpBinding_IService1" closeTimeout="00:01:00"
16:         openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
17:         bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
18:         maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text"
19:         textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
20:          <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
21:           maxBytesPerRead="4096" maxNameTableCharCount="16384" />
22:          <reliableSession ordered="true" inactivityTimeout="00:10:00"
23:           enabled="false" />
24:          <security mode="Message">
25:            <transport clientCredentialType="Windows" proxyCredentialType="None"
26:             realm="" />
27:            <message clientCredentialType="UserName" negotiateServiceCredential="true"
28:             algorithmSuite="Default" establishSecurityContext="true" />
29:          </security>
30:        </binding>
31:      </wsHttpBinding>
32:    </bindings>
33:    <client>
34:      <endpoint address="http://j-8de9be98d1184/Service1.svc" behaviorConfiguration="jacBehavior"
35:       binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IService1"
36:       contract="ServiceReference1.IService1" name="WSHttpBinding_IService1">
37:        <identity>
38:          <certificate encodedValue="AwAAAAEA.....................eGtnWJsvtFQsEuzDYw==" />
39:        </identity>
40:      </endpoint>
41:    </client>
42:  </system.serviceModel>

6.调用.

1:  ServiceReference1.Service1Client sc = new WebApplication1.ServiceReference1.Service1Client(); 
2:  sc.ClientCredentials.UserName.UserName = "jac"; 
3:  sc.ClientCredentials.UserName.Password = "jac"; 
4:  Label1.Text = sc.GetData(22);

完成.

工程文件下载:http://FunSL.com

为了便使这种方式自由度更高,以下是服务器端的纯代码版本:

 1:  using System; 
 2:  using System.Collections.Generic; 
 3:  using System.Linq; 
 4:  using System.Text; 
 5:  using System.ServiceModel; 
 6:  using System.IdentityModel.Selectors; 
 7:  using System.ServiceModel.Description; 
 8:  
 9:  namespace wcf.username 
10:  { 
11:      class Program 
12:      { 
13:          static void Main(string[] args) 
14:          { 
15:              EndpointAddress endp = new EndpointAddress("http://localhost/myservice"); 
16:  
17:              WSHttpBinding ws = new WSHttpBinding(); 
18:              ws.Security.Mode = SecurityMode.Message; 
19:              ws.Security.Message.ClientCredentialType = MessageCredentialType.UserName; 
20:  
21:              ServiceMetadataBehavior behavior = new ServiceMetadataBehavior(); 
22:              behavior.HttpGetEnabled = true; 
23:              behavior.HttpGetUrl = new Uri("http://localhost/myservice/mex"); 
24:  
25:              ServiceHost sh = new ServiceHost(typeof(serverdo), new Uri(endp.ToString())); 
26:  
27:              sh.Description.Behaviors.Add(behavior); 
28:  
29:              sh.Credentials.ClientCertificate.Authentication.CertificateValidationMode =  
30:                  System.ServiceModel.Security.X509CertificateValidationMode.None; 
31:  
32:  
33:              sh.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = 
34:                   System.ServiceModel.Security.UserNamePasswordValidationMode.Custom; 
35:  
36:              sh.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = new checkUserName(); 
37:  
38:              sh.Credentials.ServiceCertificate.SetCertificate( 
39:                  System.Security.Cryptography.X509Certificates.StoreLocation.LocalMachine,  
40:                  System.Security.Cryptography.X509Certificates.StoreName.My, 
41:                  System.Security.Cryptography.X509Certificates.X509FindType.FindBySubjectName, "MyServer"); 
42:  
43:              sh.AddServiceEndpoint(typeof(Iservice), ws, endp.ToString()); 
44:              sh.Open(); 
45:  
46:              Console.WriteLine("ok"); 
47:              Console.Read(); 
48:          } 
49:      } 
50:  
51:      class checkUserName:UserNamePasswordValidator 
52:      { 
53:          public override void Validate(string userName, string password) 
54:          { 
55:              if (userName != "jac" && password != "jac") 
56:              { 
57:                  throw new FaultException("userName and passWord be error"); 
58:              } 
59:          } 
60:      } 
61:  
62:      [ServiceContract] 
63:      interface Iservice 
64:      { 
65:          [OperationContract] 
66:          string test(string msg); 
67:      } 
68:  
69:      class serverdo:Iservice 
70:      { 
71:          #region Iservice 成员 
72:  
73:          public string test(string msg) 
74:          { 
75:              Console.WriteLine("user inter:" + msg); 
76:  
77:              return "user inter:" + msg; 
78:          } 
79:  
80:          #endregion 
81:      } 
82:  
83:  }
posted @ 2012-12-10 09:14  黎东海  阅读(271)  评论(0编辑  收藏  举报