http://www.ibm.com/developerworks/cn/data/library/techarticles/0305swart/0305swart.html
Bob Swart, Bob Swart Training & Consultancy
2003 年 8 月 01 日
本文显示了如何使用特殊的 Login 方法向 DataSnap 应用程序添加认证;指出了这一认证与 SSL 证书相结合用于提高安全性的重要性;以及描述了如何向 Web 服务器机器部署 DataSnap 服务器应用程序。
几个月前,我写了有关将 IBM DB2 ®Universal Database ™用作分布式应用程序中后端数据库的两篇文章,其中把最初的 Windows 应用程序拆成了不相同的两层:瘦客户机层和数据库服务器层。 第一篇文章使用 Delphi ™7 的 DataSnap ™作为多层体系结构,而 第二篇文章添加了 SOAP 作为通信协议,从而最终形成了可用于 Windows(使用 Delphi 和 C++Builder ®)和 Linux(Kylix ™Delphi 版和 Kylix ™C++ 版)的解决方案。
我收到了关于这两篇文章的大量反馈,主要涉及部署问题,所以我想在这篇后续文章中解决这些问题,同时扩展 DataSnap SOAP 示例。除了讲述部署的步骤之外,我还要讨论一些登录和认证方面的细节,它们可能有助于提高 DB2 后端数据库的安全性。不过我们首先讨论后一主题。
![]() ![]() |
![]()
|
在上两篇文章中,我展示了 DataSnap 客户机可以连接至 DataSnap 服务器并执行各种操作,如检索记录、更新记录、甚至删除记录,所有这些操作都不需要确认或认证。这适用于演示,但不适用于实际情况,所以这次将对 DataSnap 服务器和客户机添加较简单的安全性层(从而使您可以着手在这层周围构建甚至更为复杂的安全性层)。
TSQLConnection 组件是唯一直接与 DB2 数据库相连接的组件,TSQLConnection 组件已包含要连接至这个数据库所需的正确的用户名和密码,我已经用这样的方式(使用 TSQLConnection 组件)构建了 DataSnap 服务器。这意味着决不需要“在线路上”传递数据库用户名和密码,因而是安全的(除非有人“黑掉”了 Web 服务器并研究了 DataSnap 服务器的可执行文件,查找到用户名和密码特性)。您不需要在因特网上发送数据库用户名和密码,而应该在线路上发送特殊的“客户机”密码(禁用单个客户机比禁用数据库用户名/密码容易且影响也小)。
在很多地方 DataSnap 服务器都可以请求这样的认证,尤其是 TDataSetProvider 组件的 OnBefore 事件处理程序。这是一个组件,它实际上将来自服务器的数据(记录)发送给客户机,或根据从客户机接收到的信息来更新 DB2 表。您可以使用 OnBefore 事件处理程序来检查是否允许客户机请求记录或更新信息。
接着,您需要使用 OnBeforeGetRecords 和 OnBeforeApplyUpdates 事件处理程序“保护”服务器(使用前者请求记录,再使用后者修改服务器上的记录)。这两个事件处理程序都包含一个 OleVariant 类型的 OwnerData 参数。客户机应用程序可以在对应的 TClientDataSet 组件的 OnBefore 事件处理程序的参数中传递定制的“OwnerData”值。假定客户机应用程序已经允许最终用户输入用户名/密码,那么下面这段代码显示了 TClientDataSet 的 OnBeforeGetRecords 事件处理程序(客户机端):
procedure TForm1.ClientDataSet1BeforeGetRecords(Sender: TObject; var OwnerData: OleVariant); begin OwnerData := CodeWord; end; |
在服务器端,您首先需要检查传入的 OwnerData 不为 null(即空值),随后将它指定给 WideString 并将它与具体的 CodeWord 作比较:
const CodeWord = 'Open Sesame'; procedure TCustomerOrders.dspCustomerBeforeGetRecords(Sender: TObject; var OwnerData: OleVariant); var Str: WideString; begin if VarIsEmpty(OwnerData) or VarIsNull(OwnerData) then Str := '' else Str := OwnerData; if Str <> CodeWord then raise Exception.Create('No permission to Get Records!'); end; |
![]() ![]() |
![]()
|
实际上,您可能不单单只检查一个 CodeWord,您也许有一列实际的用户名和密码。这意味着您应该继承 DataSnap SOAP Web 服务的接口,向它添加一个 Login 方法,象下面这样:
type ID7DB2SAMPLE = interface(IAppServerSOAP) ['{E3791B81-2D4E-40C6-964E-9087AAAF35C6}'] function Login(const UserName, Password: WideString): WideString; stdcall; end; |
Login 方法的实现应该检查用户名和密码(例如,它们可以存储在列表、.ini 文件或其它安全数据库中),然后对正确的登录只返回 CodeWord。客户机应该保存这个 CodeWord 并在会话期间使用它:
function TD7DB2SAMPLE.Login(const UserName, Password: WideString): WideString; begin if (UserName = 'Bob') and (Password = 'Swart') then Result := 'Open Sesame' else Result := 'Permission Denied'; // a wrong CodeWord end; |
您可以将特殊标记添加到 CodeWord 以控制其生命期或有效性 - 象客户机的 IP 地址。(这留给您作为一个练习,您可以尝试它。)
在客户机端,您现在必须从 ID7DB2SAMPLE Web 服务调用定制方法。但是 TSoapConnection 组件只公开 IAppServerSoap 方法。要使用这个附加功能,必须从已注册的 URL(本例中可能是 http://localhost/scripts/D7DB2CGI.exe/soap/ID7DB2SAMPLE
)导入 Web 服务。
要导入使用 Delphi 7 的 Web 服务,可以使用 Delphi7//bin 目录下的 WSDLIMP 实用程序:
wsdlimp http://localhost/scripts/D7DB2CGI.exe/wsdl/ID7DB2SAMPLE |
或者使用对象资源库(Object Repository)的 WSDL Importer(执行 File | New - Other操作并转至 WebServices选项卡):
这两种情况都会产生一个新单元 ID7DB2SAMPLE1.pas,它包含带有 Login 方法的 ID7DB2SAMPLE 的接口定义。为了使用这个接口并调用 Login 方法,您必须从 Component Palette 的 WebServices 选项卡将 THTTPRIO 组件添加到我们的客户机表单,并将其 URL 特性设置成 http://localhost/scripts/D7DB2CGI.exe/soap/ID7DB2SAMPLE
。
有了这个 THTTPRIO 组件,就可以连接至 Web 服务,调用 Login 方法以及保存生成的 CodeWord,这样您就可以将 CodeWord 用于随后的 OnBeforeGetRecords 和 OnBeforeApplyUpdates 事件处理程序。以下是调用 Login 的代码(源归档文件中有完整的代码):
procedure TForm1.FormCreate(Sender: TObject); begin with (HTTPRIO1 as ID7DB2SAMPLE) do CodeWord := Login('Bob', 'Swart'); cdsEMP.Active := True end; |
很显然,在我传递字符串‘Bob’和‘Swart’的位置,最终用户需要使用对话框来输入这个会话的用户名和密码(这是您可以尝试的另一个练习)。
![]() ![]() |
![]()
|
在不安全的连接上发送用户名和密码不是一个好主意 - 即使只发送一次,也不是好主意,就如我在最后一个示例中做的那样。您应该始终尝试使用安全的连接来发送认证信息,幸运的是,您可以对此使用安全套接字层(Secure Sockets Layer,SSL)连接。它包含两步:第一步是在已安装 DataSnap SOAP 服务器的 Web 服务器上安装 SSL 证书(前提是如果该机器上没有 SSL 证书)。而第二步则更为简单:转到 SOAP Web 模块,选择 TWSDLHTMLPublish 组件,然后将 PublishOptions 特性的 poPublishLocationAsSecure 标志设置成 True。自此,这个 Web 服务将需要 https://
才能够连接至该服务器(而不是 http://
),并且加密客户机和这个服务器之间的所有信息。
与您的 Web 管理员联系,以获取有关您的 Web 服务器上 SSL 证书可用性的更多信息。
![]() |
|
![]() ![]() |
![]()
|
在论及 DataSnap SOAP 服务器的部署时,根据 Web 服务器应用程序的目标,实际上可以有几种选择(在您启动一个新的 SOAP 服务器应用程序时,您可以进行选择:请参阅 上一篇文章)。
最简单的部署是 CGI 独立可执行文件,它也是我在本文中所使用的 D7DB2SAMPLE 服务器应用程序的目标。需要将 CGI 独立可执行文件部署到 Web 服务器的(虚拟)目录中,已经对该目录的脚本编制权限进行了设置(在 Windows 上),或者已经设置了可执行文件的执行位(在 Linux 上)。
另外,在 Windows 上,您可以选择 ISAPI 动态链接库目标。CGI 可执行文件和 ISAPI DLL 之间的差别在于后者只装入一次(在第一个请求时),在您真正关闭 Web 服务器之前,它一直存在于内存中。这样做的优势在于性能:您不必为每个进入请求创建 SOAP 数据模块并连接至数据库。缺点在于缺乏灵活性:如果您想更新或更改 ISAPI DLL(例如,使用新功能),那么在可以替换 ISAPI DLL 之前,您先要关闭 Web 服务器进程(CGI 可执行文件可以被重写,但是 ISAPI DLL 将处于“使用中”状态,因此操作系统将拒绝重写它)。
您可以通过 Microsoft 的因特网信息服务(Internet Information Service,IIS)使用 ISAPI DLL,但也可以为 Windows 或 Linux 上的 Apache Web 服务器创建 Apache 共享模块(请参阅 www.apache.org,获取有关这方面的更多信息)。
最后,您可以构建的 Web App Debugger 目标专门作为调试目标,您可以在其中测试 DataSnap SOAP 服务器,而不必去真正部署它。不管哪种情况,DataSnap SOAP 服务器都必须能连接至 DB2 数据库(在我们的示例中是 SAMPLE 数据库),所以请确保在 TSQLConnection 特性中指定了正确的数据库名称、用户名和密码,并确保 DataSnap SOAP 服务器可以找到 DB2 客户机 db2cli.dll
。
![]() ![]() |
![]()
|
本文中,我已经展示了如何使用特殊的 Login 方法将认证添加到 DataSnap 应用程序,该方法返回一个标识(或 CodeWord),我们必须将此标识(即 CodeWord) - 它作为 OwnerData 的一部分 - 传递给随后的 OnBeforeGetRecords 和 OnBeforeApplyUpdate 事件处理程序。我还指出了将认证与 SSL 证书相结合从而提高安全性的重要性。
最后,我略微详细地描述了在 Web 服务器机器(可以是 Windows 或 Linux)上如何部署 DataSnap 服务器应用程序。这使得在任何地方运行的瘦客户机都可以使用您的 DB2 数据库。
在以后的文章中,我将探究 Borland C#Builder ™ IDE for .NET 上的 DB2 UDB 使用,下回见。
![]() ![]() |
![]()
|
描述 | 文件类型 | 文件大小 | 下载方法 |
SoapClient.zip | zip | 7 KB | HTTP ![]() |
SoapServer.zip | zip | 5 KB | HTTP ![]() |
![]() | ||
| ![]() | Bob Swart(也称为 Dr.Bob - www.drbob42.com)在他自己的公司 Bob Swart Training & Consultancy(eBob42)(位于荷兰 Helmond)的身份是作家、教员、顾问和 Web 管理员。Bob 编写了自己的 Delphi 培训教材,并且从 1993 年以来一直在 Delphi 和 Borland 开发者大会上发表演讲。Bob 已经撰写了数百篇文章,并且还是 Revolutionary Guide to Delphi 2、 Delphi 4 Unleashed、 C++Builder 4 Unleashed、 C++Builder 5 Developer's Guide、 Kylix Developer's Guide、 Delphi 6 Developer's Guide和即将出版的 C++Builder 6 Developer's Guide的合著者。 |