WCF(安全认证)通过MembershipProvider进行用户名/密码的认证

最近搞个项目,需要用到WCF来构建服务层,所以考虑到WCF的安全认证了。

WCF的身份认证模式分为

     1. 无身份验证:         所有的调用者都能访问服务

     2.Windows身份验证:Kerberos(有域服务器)和NTLM(工作组)

     3.用户名与密码:       客户端向服务端发送一个用户名和密码,服务端通过一些凭证库来验证

     4.X509证书:           客户端包含一个证书,服务端预先知道这些证书,当客户端发送请求时,服务端会验证客户端的证书

     5.定制机制:            允许开发者任意使用一种身份验证机制

     6.发布口令:             调用者与服务同事依赖一个安全口令

在这里我只描述一下通过MembershipProvider进行用户名/密码的认证

①先建立契约类库Contract具体代码如下

 

ExpandedBlockStart.gif View Code
 1  using System;
 2  using System.Collections.Generic;
 3  using System.Text;
 4  using System.ServiceModel;
 5 
 6  namespace Contracts
 7 {
 8     [ServiceContract]
 9      public  interface IServiceHosting
10     {
11          ///   <summary>
12           ///  加法
13           ///   </summary>
14           ///   <param name="x"></param>
15           ///   <param name="y"></param>
16           ///   <returns></returns>
17          [OperationContract]
18          double ADD( double x,  double y);
19 
20          ///   <summary>
21           ///  减法
22           ///   </summary>
23           ///   <param name="x"></param>
24           ///   <param name="y"></param>
25           ///   <returns></returns>
26          [OperationContract]
27          double substruction( double x,  double y);
28 
29          ///   <summary>
30           ///  乘法
31           ///   </summary>
32           ///   <param name="x"></param>
33           ///   <param name="y"></param>
34           ///   <returns></returns>
35          [OperationContract]
36          double multiplication( double x,  double y);
37 
38          ///   <summary>
39           ///  除法
40           ///   </summary>
41           ///   <param name="x"> 被除数 </param>
42           ///   <param name="y"> 除数 </param>
43           ///   <returns></returns>
44          [OperationContract(Name =  " division ")]
45          double division( double x,  double y);
46     }
47 }

第二步 建立 服务类,Service 继承,契约Contract类库里的IServiceHosting接口

 

ExpandedBlockStart.gif View Code
 1  using System;
 2  using System.Collections.Generic;
 3  using System.Text;
 4  using Contracts;
 5 
 6  namespace Service
 7 {
 8      public  class ServiceHosting : IServiceHosting
 9     {
10          public  double ADD( double x,  double y)
11         {
12              return x + y;
13         }
14 
15          public  double substruction( double x,  double y)
16         {
17              return x - y;
18         }
19 
20          public  double multiplication( double x,  double y)
21         {
22              return x * y;
23         }
24 
25          public  double division( double x,  double y)
26         {
27              if (y ==  0)
28             {
29                  throw  new Exception( " 除数不能为零 ");
30             }
31              else
32             {
33                  return x / y;
34             }
35         }
36     }
37 }

第三步建立服务主机Hosting控制台程序

 

ExpandedBlockStart.gif View Code
 1  using System;
 2  using System.Collections.Generic;
 3  using System.Text;
 4  using System.Web.Security;
 5  using System.ServiceModel;
 6  using Contracts;
 7  using Service;
 8 
 9  namespace Hosting
10 {
11      class Program
12     {
13          static  void Main( string[] args)
14         {
15              try
16             {     //判断数据库里是否有Sytech这个用户,没有就添加一条
17                  if (Membership.FindUsersByName( " Sytech ").Count ==  0)
18                 {
19                     Membership.CreateUser( " Sytech "" ASD!@#123 "" Sytech@sytech.com.cn ");
20                 }
21                  using (ServiceHost host =  new ServiceHost( typeof(ServiceHosting)))
22                 {
23                     host.Opened +=  delegate
24                     {
25                         Console.WriteLine(host.BaseAddresses[ 0].ToString());
26                     };
27                     host.Open();
28                     Console.WriteLine( " Host start ");
29                     Console.Read();
30                 }
31             }
32              catch (Exception ex)
33             {
34                 Console.WriteLine(ex.Message);
35                 Console.Read();
36             }
37         }
38     }
39 }

在这里说明一下啊,这次是通过MembershipProvider来进行密码/用户名的认证,所以需要先生成aspnetdb数据库,这个大家都知道怎么来搞,不知道的可以去baidu查一下。创建出来的数据表可以同时服务于多个应用,所有每一个表中都具有一个名称为ApplicationId的字段来明确该条记录对应的应用。而所有应用记录维护在aspnet_Applications这么一个表中。现在我们需要通过执行下面一段SQL脚本在该表中添加一条表示我们应用的记录

1: INSERT INTO [aspnet_Applications]  
2:            ([ApplicationName] 
3:            ,[LoweredApplicationName]  
4:            ,[ApplicationId]  
5:            ,[Description])  
6: VALUES  
7:            (  
8:              'Demo'  
9:              ,'demo' 
10:              ,NEWID() 
11:              ,'' 
12:         )

 经过这三步,就可以建立服务器端的开发就完成,现在我们来配置服务器端。

  服务器端的配置主要是Config的配置,在配置前我们先在服务器上生成服务证书,

制作证书  makecert -r -pe -n "CN=FrankWCFServer" -ss My -sky exchange 通过这个来生成证书(默认是在currentuser,Config里配置就是storeLocation="CurrentUser",如果使用makecert -r -pe -n "CN=FrankWCFServer" -ss My -sky exchange -sr LocalMachine,那么证书就存放在本地计算机的个人里 Config里配置就是storeLocation="LocalMachine",证书生成后可以在mmc里,添加/或删除管理单元-》证书-添加-》当前用户-》确定,就可以在  个人和受信任的根证书颁发机构 里找到你创建的FrankWCFServer证书。下来配置服务器端的Config。

 

ExpandedBlockStart.gif View Code
 1 <?xml version= " 1.0 " encoding= " utf-8 " ?>
 2 <configuration>
 3   <connectionStrings>
      //数据库连接字符串
 4     <add name= " aspnetdb " connectionString= " Server=.; Database=aspnetdb; Uid=sa; Pwd=123456 "/>
 5   </connectionStrings>
 6   <system.web>
 7     <membership defaultProvider= " myProvider ">
 8       <providers>//Membership的配置 整个项目使用的.netFramwork3.0
 9         <add name= " myProvider " type= " System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a "
10              connectionStringName= " aspnetdb " applicationName= " MembershipAuthenticationDemo " requiresQuestionAndAnswer= " false " />
11       </providers>
12     </membership>
13   </system.web>
14   <system.serviceModel>
15     <services>
16       <service name= " Service.ServiceHosting " behaviorConfiguration= " HostBehaviors ">
17         <endpoint address= "" binding= " wsHttpBinding " bindingConfiguration= " userNameCredentialBinding " contract= " Contracts.IServiceHosting " />
18         <host>
19           <baseAddresses>//将Contract和Service 在800端口下发布
20             <add baseAddress= " http://win-opvvg1v8458:800/ServiceHosting "/>
21           </baseAddresses>
22         </host>
23       </service>
24     </services>
25     <behaviors>
26       <serviceBehaviors>
27         <behavior name= " HostBehaviors ">
28           <serviceCredentials>
                 //证书
29             <serviceCertificate storeLocation= " CurrentUser " storeName= " My "  x509FindType= " FindBySubjectName " findValue= " FrankWCFServer "/>
                //Membership
30             <userNameAuthentication userNamePasswordValidationMode= " MembershipProvider " membershipProviderName= " myProvider "/>
31           </serviceCredentials>
32           <serviceMetadata httpGetEnabled= " true "/>
33         </behavior>
34       </serviceBehaviors>
35     </behaviors>
36     <bindings>
37       <wsHttpBinding>
38         <binding name= " userNameCredentialBinding ">
39           <security mode= " Message ">
40             <message clientCredentialType= " UserName "/>
41           </security>
42         </binding>
43       </wsHttpBinding>
44     </bindings>
45   </system.serviceModel>
46 </configuration>

•配置名称为AspNetDb的连接字符串连接的是我们刚刚创建的数据库,并通过aspnet_regsql.exe工具在该数据库中创建了所需的数据库对象;
•表示Membership配置节的<system.web>/<membership>节点下配置了唯一的SqlMembershipProvider,配置名称为myProvider。上面配置的连接字符创名称AspNetDb配置在connectionStringName属性中,意味着该SqlMembershipProvider会将我们创建的数据库作为用户帐号存储;
•服务终结点采用WSHttpBinding,采用Message安全模式,客户端凭证类型被设置为UserName;
•服务应用了一个配置名称为membershipAuthentication的服务行为,该行为中通过<serviceCertificate>节点设置了服务证书。在表示用户名/密码认证配置的<userNameAuthentication>节点中,将认证模式设置成MembershipProvider,而membershipProviderName属性的值为我们在<system.web>/<membership>中设置的MembershipProvider的名称。

到目前为止,在我们创建的数据库中并没有用户帐户记录。为了演示认证的效果,我们必须创建相关用户帐户记录。为了省事,我直接将相关的代码写在了服务寄宿的代码中。如下面的代码片断所示,在对服务进行寄宿之前,我通过调用Membership的静态方法CreateUser创建了一个用户名、密码和Email分别为"Sytech""ASD!@#123"Sytech@sytech.com.cn。这就是我们为什么在Hosting里开始就写

 if (Membership.FindUsersByName("Sytech").Count == 0)
   {
                    Membership.CreateUser("Sytech", "ASD!@#123", "Sytech@sytech.com.cn");
   }

现在服务器端就可以告一段落。我们来启动Hosting之后可以在浏览器里输入http://win-opvvg1v8458:800/ServiceHosting可以看到如下的页面。

服务器端配置成功。

客户端的调用,在这里建一个控制台应用程序Client,添加服务引用,在地址里输入http://win-opvvg1v8458:800/ServiceHosting点击确定。引用成功Client的Config文件自动配置完成。

然后可以调用了。具体代码如下

ExpandedBlockStart.gif View Code
 1  using System;
 2  using System.Collections.Generic;
 3  using System.Text;
 4  using System.ServiceModel.Security;
 5  using System.ServiceModel;
 6  using Contracts;
 7 
 8  namespace Client
 9 {
10      class Program
11     {
12          static  void Main( string[] args)
13         {           
14             Ssss.ServiceHostingClient client =  new Ssss.ServiceHostingClient();
15             UserNamePasswordClientCredential uncc = client.ClientCredentials.UserName;
16             uncc.UserName =  " Sytech ";
17             uncc.Password =  " ASD!@#123 ";
18             Console.WriteLine(client.ADD( 103).ToString());
19             Console.Read();
20         }
21     }
22 }

客户端代码完成,客户端config是在添加引用服务的时候自动添加成功的。不需要配置的。

现在可以运行,客户端程序看看有什么异常!不错,出现异常。这是因为客户端没有导入 服务器端生成的证书。

服务器端创建的FrankWCFServer这证书,需要导出来FrankWCFServer.cer,将导出来证书,安装在客户端PC上分别安装在当前用户的个人和受信任的根证书颁发机构里,然后在运行客户端程序一看OK了。 

在此声明一下,我是一个WCF的初学者,这次的配置是在服务器和客户端两台机器上做的配置,搞了2天,刚才调通,好多东西都不懂,还在学习中,这只是一个笔记,懒得记在本子上,希望看到的别拍砖就行,先行谢过。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

转载于:https://www.cnblogs.com/Employee/archive/2011/12/08/2281242.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值