这部分将关注因特网上的安全服务。图片8.6显示了一个通过因特网访问服务的Windows应用程序。这个图片开始重点突出微软公司的软件 + 服务模式,就是你在桌面运行客户端应用程序且可以访问因特网上的服务。这些类型的应用程序需要管理来自因特网的用户的架构。这包括验证并授权来自因特网的用户。这个类型的应用的典型方式是使用一个数据库来存储用户名,密码和角色。有很多理由来做这个,包括账户管理,安全范围和备份还原的易用性。ASP.NET 2.0 通过应用层提供诸如成员关系和基于角色授权的能力。WCF与这些对用户认证和授权的应用层服务集成到一起。这意味着开发人员可以对ASP.NET中很多开箱提供者重用来管理对WCF服务的访问。
我们将查看一个简单的应用程序来了解与ASP.NET集成。这个应用程序刚好是一个使用ASP.NET创建的Web 应用。这些能力不是仅绑定到一个Web 应用它们也可以很容易的绑定到一个Windows桌面应用程序中。图片8.7显示了一个使用ASP.NET创建用来在本章突出特性的简单应用程序。这个应用程序显示了一个游戏列表并允许用户登录和回顾他们的最喜爱的游戏。这个应用程序的前提是匿名用户和注册用户都可以查看游戏和历史记录。只有已经登录的注册用户可以添加视图,只有管理员们可以修改视图。关于这个应用程序的更多细节将会在第十三章”可编程站点”中介绍。
图片8.6 Windows应用程序与因特网上的服务
图片8.7 因特网应用程序示例
因为这个一个网络应用程序,我们也将探讨窗体认证和如何使用窗体认证来处理在一个基于HTTP的终结点上寄宿的服务HTTP cookie的认证请求。
ASP.NET 集成
ASP.NET 和WCF在激活服务和宿主模型上有稍微的差别。WCF被设计成使用一系列传输协议来支持服务激活,比如TCP,HTTP和MSMQ,而ASP.NET原始被设计成在HTTP协议上激活服务。WCF也被设计成支持多个不同的宿主模型,包括自我寄宿也包括在因特网信息服务(IIS)内部的寄宿。当在IIS内部寄宿时,WCF可以直接接收消息或者使用一个ASP.NET兼容模式。默认的模式是与ASP.NET在同样的AppDomain运行端到端.这允许WCF在跨寄宿环境和传输协议上保持行为一致。 如果你不关心这个而且仅需要HTTP,WCF可以保留ASP.NET兼容模式来访问ASP.NET的一些能力。ASP.NET兼容模式允许WCF服务访问ASP.NET运行时能力,比如HttpContext对象,文件和URL. 授权以及HTTPModule扩展。列表8.28显示了在配置文件内部如何使能ASP.NET兼容模式。
列表8.28 设置ASP.NET 兼容模式(在web.config中)
<system.serviceModel> <serviceHostingEnvironment aspNetCompatibilityEnabled="true" /> </system.serviceModel>
服务也可以注册无论它们是否要求使用ASP.NET兼容模式。这个通过在服务端使用AspNetCompatibilityRequirementsAttribute 属性实现的。列表8.29显示了设置这个属性的一个服务端的例子。这个服务的很多代码为了简洁的目的被移除掉。
列表8.29 ASP.NET CompatibleRequirements 属性(在web.config中)
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
理解ASP.NET兼容模式不总是需要的是重要的。例如,我们将检查如何实现ASP.NET成员关系提供方来认证WCF服务的访问。这个特性不要求使用ASP.NET兼容模式。然而,如果你想从ASP.NET HttpContext中访问一个用户的职责和身份,或者使用另外的安全相关的特性比如文件和URL授权,你将需要使用ASP.NET兼容模式。在这一部分,WCF服务更多充当ASP.NET 网络服务因为它们有类似的功能。一个重要的问题是如果你的内容要在IIS外面或者使用非HTTP的传输协议的服务中寄宿你不应该使用ASP.NET兼容模式。
使用组成员关系提供者进行认证
ASP.NET 2.0 提供很多服务比如组成员关系,角色,摘要以及更多。这些服务是开发人员可以直接使用而不用写额外代码的预先创建好的架构。例如,组成员关系服务提供管理用户的功能,包括创建,删除和更新用户。ASP.NET也允许窗体认证功能使用组成员关系服务来为Web 应用认证用户。
WCF提供一个类似的架构来对不能使用组成员服务认证的用户提供服务认证。这个功能的使用不用考虑是否有一个ASP.NET Web 应用。这意味着任何ASP.NET 组成员服务都可以用来认证对一个WCF服务的访问权限。因为组成员服务为用户管理提供它自己的架构,我们需要使用用户名令牌。列表8.30给出了一个使用用户名令牌来认证它的用户的绑定的例子。用户名令牌是未加密的,因此它们需要使用传输层加密或者消息层加密方法来加密。这个例子显示了使用传输层加密,它是更通用的场景。注意在这个场景中WCF要求使用加密是重要的,所以跳过加密过程是不是随意的。
列表8.30 使用用户名/密码证明(在web.config中)
<bindings> <wsHttpBinding> <binding name="MembershipBinding"> <security mode="TransportWithMessageCredential"> <transport proxyCredentialType="Windows"> <extendedProtectionPolicy policyEnforcement="Never" /> </transport> <message clientCredentialType="UserName" /> </security> </binding> </wsHttpBinding> </bindings>
使用ASP.NET组成员关系服务的下一步是配置一个使用一个组成员关系提供者进行用户名认证的服务行为。我们将使用System.Web.Security.SqlMembershipProvider, 它使用SQL Server作为存储和收集用户信息的架构。列表8.31显示了如果确定一个不使用ASP.NET组成员提供者进行认证用户的服务行为。
列表8.31使用SQL 组成员提供者的服务认证(在web.config中)
<behaviors> <serviceBehaviors> <behavior name="myServiceBehavior"> <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="false" /> <serviceCredentials> <userNameAuthentication userNamePasswordValidationMode="MembershipProvider" membershipProviderName="AspNetSqlMembershipProvider" /> </serviceCredentials> </behavior> </serviceBehaviors> </behaviors>
列表8.31为SQL Server 使用默认的ASP.NET 组成员提供者。列表8.32显示了ASP.NET组成员关系提供者在machine.config中的默认配置。
列表8.32 组成员关系提供者配置(在machine.config 中)
<system.web> <processModel autoConfig="true"/> <httpHandlers/> <membership> <providers> <add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="LocalSqlServer" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="true" applicationName="/" requiresUniqueEmail="false" passwordFormat="Hashed" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="7" minRequiredNonalphanumericCharacters="1" passwordAttemptWindow="10" passwordStrengthRegularExpression=""/> </providers> </membership> <profile> <providers> <add name="AspNetSqlProfileProvider" connectionStringName="LocalSqlServer" applicationName="/" type="System.Web.Profile.SqlProfileProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/> </providers> </profile> <roleManager> <providers> <add name="AspNetSqlRoleProvider" connectionStringName="LocalSqlServer" applicationName="/" type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/> <add name="AspNetWindowsTokenRoleProvider" applicationName="/" type="System.Web.Security.WindowsTokenRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/> </providers> </roleManager> </system.web>
一个公共的开发任务是使用一个自我签名证书建立传输加密。WCF将尝试验证证书然后失败并报出下面的错误:
“无法使用’localhost’授权为SSL/TLS安全信道创建可信赖关系。”
查看内部异常信息显示远程证书验证失败。下面是抛出的原始异常信息:
“根据认证过程远程证书不合法。”
列表8.33显示如何对无法认证的证书强制进行验证,比如一个自我签名证书。这份代码应该被客户端实现而且应该仅在开发环境中用于测试目的。
列表8.33 使用自我签名证书开发
class Program { static void Main(string[] args) { Console.WriteLine("Press ENTER to make service call."); Console.ReadLine(); Samples.SamplesClient proxy = new Client.Samples.SamplesClient(); proxy.ClientCredentials.UserName.UserName = @"administrator"; proxy.ClientCredentials.UserName.Password = @"1"; System.Net.ServicePointManager.ServerCertificateValidationCallback += new System.Net.Security.RemoteCertificateValidationCallback(RemoteCertValidate); try { Console.WriteLine(proxy.GetPublicCode()); Console.WriteLine(proxy.GetMemberCode()); Console.WriteLine(proxy.GetSecretCode()); } catch (Exception ex) { Console.WriteLine("exception = " + ex.Message); } Console.ReadLine(); } //Should be used only in development for testing purposes. static bool RemoteCertValidate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors error) { return true; }