[WCF安全系列]谈谈WCF的客户端认证[用户名/密码认证]
对于基于Internet的应用,基于用户名和密码的认证方式是最为常用的,而WCF为你提供了不同模式的用户名认证方式。首先还是从用户凭证的表示说起。
一、用户名/密码认证的三种模式
基于用户名/密码的用户凭证通过类型UserNamePasswordClientCredential表示。而在ClientCredentials中,只读属性UserName表示这样一个用户凭证。你可以按照Windows凭证的方式为ChannelFactory<TChannel>或者ClientBase<TChannel>基于用户名/密码凭证。1: public class ClientCredentials
2: {
3: //其他成员
4: public UserNamePasswordClientCredential UserName { get; }
5: }
6: public sealed class UserNamePasswordClientCredential
7: {
8: //其他成员
9: public string Password {get; set; }
10: public string UserName { get; set; } 11: }
用户名/密码凭证在客户端的设置很容易,但是我们关心的是服务端采用怎样的机制来验证这个凭证。WCF为你提供了如下三种方式来验证凭证中用户名是否和密码相符:Windows:将用户名和密码映射为Windows帐号和密码,采用Windows认证;
MembershipProvider:利用配置的MembershipProvider验证用户名和密码;
自定义:通过继承抽象类UsernamePasswordValidator,自定义用户名/密码验证器进行验证。
WCF通过枚举UserNamePasswordValidationMode定了上述三种用户名/密码认证模式。该枚举定义如下,其中Windows是默认选项。1: public enum UserNamePasswordValidationMode 2: { 3: Windows, 4: MembershipProvider, 5: Custom 6: }
上述三种认证模式的设置最终通过之前提到过的ServiceCredentials这一服务行为进行设置的。从下面的定义我们可以看出,ServiceCredentials定义了只读属性UserNameAuthentication用于基于用户名/密码认证的相关设置。属性的类型为UserNamePasswordServiceCredential,定义其中的UserNamePasswordValidationMode属性表示采用的认证模式。如果选择了需要通过属性MembershipProvider设置采用的MembershipProvider。如果选择了Custom,则需要通过CustomUserNamePasswordValidator属性指定你自定义的UserNamePasswordValidator对象。1: public class ServiceCredentials: SecurityCredentialsManager, IServiceBehavior
2: {
3: //其他成员
4: public UserNamePasswordServiceCredential UserNameAuthentication { get; }
5: }
6: public sealed class UserNamePasswordServiceCredential
7: {
8: //其他成员
9: public UserNamePasswordValidator CustomUserNamePasswordValidator { get; set; }
10: public MembershipProvider MembershipProvider { get; set; }
11: public UserNamePasswordValidationMode UserNamePasswordValidationMode { get; set; }
12: }
接下来我们通过实例演示的方式来如何通过MembershipProvider进行基于用户名/密码认证,而对于自定义UserNamePasswordValidator的实例我会在介绍安全会话的时候进行演示。二、实例演示:通过MembershipProvider进行用户名/密码的认证
Membership是ASP.NET中一个重要的模块,旨在进行基于用户名/密码的认证和对应的帐号管理。Membership采用策略设计模式,所有的API通过几个静态Membership类暴露出来,而相应的功能实现在具体的Membership提供者中。所有的提供者继承自同一个抽象类MembershipProvider。ASP.NET提供了两种类型的提供者:SqlMembershipProvider和ActiveDirectoryMembershipProvider。前者将用户存储于SQL Server数据库中,而后者则直接建立在AD之上,本实例采用SqlMembershipProvider,在前面一个实例演示中,我们创建了以计算服务为场景的解决方案,现在我们直接沿用它。我们首要的任务是在用于存储帐户信息的SQL Server数据库,为此你可以先在本地SQL Server创建一个空的数据库(假设起名为AspNetDb)。你接着需要在该数据库中创建SqlMembershipProvider所需的数据表和相应的存储过程。这些数据库对象的创建,需要借助aspnet_regsql.exe这个工具。你只需要以命令行的方式执行如下aspnet_regsql.exe(无需任何参数),相应的向导就会出现。
在向导弹出的前两个窗体中保持默认设置,直接点击“下一步”后,会出现一个数据库选择窗体。此时你需要选择我们刚刚创建的数据库,点击“确认”后,相关的数据库对象会为你创建出来。
这些创建出来的数据表可以同时服务于多个应用,所有每一个表中都具有一个名称为ApplicationId的字段来明确该条记录对应的应用。而所有应用记录维护在aspnet_Applications这么一个表中。现在我们需要通过执行下面一段SQL脚本在该表中添加一条表示我们应用的记录。我们应用起名为MembershipAuthenticationDemo。
1: INSERT INTO [aspnet_Applications]
2: ([ApplicationName]
3: ,[LoweredApplicationName]
4: ,[ApplicationId]
5: ,[Description])
6: VALUES
7: (
8: MembershipAuthenticationDemo
9: ,membershipauthenticationdemo
10: ,NEWID()
11: ,
12: )
现在数据库方面已经准备就绪,我们接着来完成编程和配置方面的工作。我们不打算从新创建一个解决方案,而是直接对之前演示的实例进行改造。我们采用自我寄宿的方式,由于Membership隶属于ASP.NET,所以我们需要添加System.Web.dll的引用,如果你采用的是.NET Frameowrk 4.0(本例所示的配置也是基于该版本),你还需额外添加对System.Web.ApplicationServices.dll的引用。接下来,我们需要在服务寄宿方面所做的工作就是将下面一段配置整个拷贝到app.config中。1: <?xml version="1.0"?>
2: <configuration>
3: <connectionStrings>
4: <add name="AspNetDb" connectionString="Server=.; Database=AspNetDb; Uid=sa; Pwd=password"/>
5: </connectionStrings>
6: <system.web>
7: <membership defaultProvider="myProvider">
8: <providers>
9: <add name="myProvider" type="System.Web.Security.SqlMembershipProvider, System.Web, Version=4.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: <bindings>
16: <ws2007HttpBinding>
17: <binding name="userNameCredentialBinding">
18: &
补充:综合编程 , 安全编程 ,