级别: 初级 马 国耀, 软件工程师, IBM
2009 年 9 月 24 日 本文将向读者介绍两个方面的内容,如何通过 WebSphere DataPower 实现服务组装,以及如何对一组服务统一安全控制,日志,计费等操作。本文涉及如何在 WebSphere DataPower 中访问外部服务,XSLT 编程扩展以及加密解密,并会使用到 WebSphere DataPower 的 XML Firewall 和 WS-Proxy,其中的设计方法和大部分代码都可以直接使用在类似的业务场景中。
WebSphere DataPowe 介绍
 | |
您可以通过以下链接了解 DataPower 及其他 ESB 产品的更多技术信息:
|
|
WebSphere DataPower 是一款可以提供高级安全,加速 XML 处理 (XML acceleration) 的 SOA 设备,也是 IBM ESB 产品中非常重要的产品之一。欲了解 IBM ESB 产品及产品之间的比较,请参考:IBM ESB 产品之间的比较及应用场景,本文向读者展示 WebSphere DataPower 的另外两个重要功能:服务组装和服务控制,我们将在下文对这两个概念进行详细描述并对此进行设计实现。
在 SOA 环境里,服务是最基本的元素。一方面,SOA 鼓励通过服务的重用来减低新应用系统的开发成本,或者通过服务组装的方式由细粒度的服务组装成粗粒度的服务,甚至业务流程,从而实现服务整合;另一方面,服务控制是 SOA 中又一非常重要的概念。对于服务的使用,特别是跨企业领域的服务访问,安全和计费都是非常重要的控制要素。本文就是从这两个主题出发来介绍 WebSphere DataPower 如何助力企业的 SOA 实施。
服务组装
服务组装是 SOA 中实现服务重用的一个很重要的手段。服务分为原子服务和复合服务。所谓原子服务就是一个独立的,自包含的细粒度服务,由多个原子服务组装在一起提供一个粒度稍大的功能的服务。通过服务组装,原子服务就获得了重用。下面介绍一个服务组装的使用场景。
通常,当一个组织把服务暴露出来供第三方使用,也会按流量收取一定的服务使用费用。在即将实现的场景中,有两个原子服务:费用服务(FeeService),折扣服务(DiscountService)。每次服务使用时,首先要根据访问的服务名字获得需付的费用,然后根据客户的类型获得折扣,最后根据费用和折扣信息进行实际的计费操作,这两个服务可以组装成一个计费服务 ChargeService,如图 1 所示:
图 1. 服务组装示意图
服务控制
在 ESB 存在的环境里,服务的调用者和服务的提供者被 ESB 分开,服务的请求消息流和返回消息流都会流经 ESB 中介。所谓服务控制指的是在 ESB 之上,我们可以对服务增加一些控制性的操作,如验证用户是否具有访问服务的权限,对流经的消息做日志操作,审计等等。
在很多应用场景下,一组业务服务可能具有一定的相似性,并有需要对这组服务的访问统一进行某些控制。在企业级解决方案中,要统一控制的操作可能更多,这里仅仅列举出其中几个典型的需求,也是在实际客户实施的过程中碰到的一些,比如:
-
验证客户端是否有权限使用将访问的服务
-
为服务的访问记录日志
-
服务使用的计费操作
下面我们将介绍服务控制的一种使用场景。从客户端的视角来看,服务的提供者就是 WebSphere DataPower,而真实的服务提供者是 WebSphere DataPower 后面的应用服务器,如 WebSphere Application Server(简称 WAS)。在客户端访问 WAS 的服务必须经过 WebSphere DataPower,而服务的控制就是在它之上进行的。
本文的场景有两个方面的控制:
-
客户端使用服务之前,一定要和 WebSphere DataPower 建立一个握手,在在这个握手的过程中,服务方会发送给客户端一个加密的标识(token),在后续的服务调用过程中,每次的服务调用都需要附带它。这个 token 就可以用来对服务的请求做有效性控制,它包含了双方的合约信息,这个 token 中可以包含很多信息,比如服务端为用户产生的 session 信息,session 有效时限等等。
-
对于任何一次的服务请求,都要调用上文所描述的计费服务,这是第二种控制。真实的场景中,可能用户的余额不足,那么在调用计费服务的过程中会产生异常,这样在 WebSphere DataPower 就可以拒绝该请求继续使用后台的部署在 WAS 上的真实服务。
服务接口的设计与实现
针对上文对服务组装以及服务控制的描述,接下来我们会根据上文的场景描述设计服务接口,并且在 DataPower 上进行实现。
服务组装
接口描述
首先给出这三个服务的接口描述。在本文的场景中,为了更清晰地描述核心内容,对服务的接口做了简化处理。
FeeService: 是一个 J2EE 应用,它提供的功能是查询数据库表,获得针对不同的服务使用应收取的费用信息。本文中提供了一个模拟的服务,这个服务没有真正查询数据库。这个模拟服务在一个 Web 工程中实现,可以部署到 WAS 服务器之上,从 这里 可以下载可直接部署的源文件。FeeService 的接口如下图所示:
图 2. FeeService 接口描述
DiscountService: 是一个规则服务,可以用 ILOG 和 WPS 中的规则引擎实现,不过在本文中,我们将这个服务也部署成 J2EE 应用并和 FeeService 放在同一个工程中。这个服务接受两个参数,其一是服务的名字,其二是用户的 Id,在示例服务中,根据这两个参数产生一个折扣率。DiscountService 的接口如下图所示:
图 3. DiscountService 接口描述
FeeDuductionService: 实施扣费的服务,这个服务针从客户的账户实际扣除费用。接口描述如图所示:
图 4. FeeDuductionService 接口描述:
ChargeService: 将要在 WebSphere DataPower 上组装的服务,这个服务获取从客户端传过来的信息,包括 FeeService 以及 DiscountService 所需要的所有信息(serviceName,usageBegin,usageEnd, clientID),返回给客户端的是真正要收取的费用也就是打折后的服务使用费以及实际的扣费操作的执行结果。ChargeService 的接口如下图所示:
图 5. ChargeService 接口描述
接下来我们可以将本文提供的 Web 工程部署(包含 Discount)到 WAS 之上,然后测试服务是否已经连通,这个步骤请读者自行完成。
实现
这个部分介绍如何在 WebSphere DataPower 上组装服务,形成一个复合服务,我们使用 WebSphere DataPower 上的 XML Firewall 来实现这个功能。
在 WebSphere DataPower 中存在这样的两个模块,为开发人员提供了丰富的编程扩展能力,这两个模块是:
1. 扩展的 XSLT,扩展了 XSLT1.0 能力。
2. WebSphere DataPower 的扩展函数和元素等。
这两个模块都可以在 XSLT 中用于实现特定的功能。下面介绍如何在 XSLT 中使用这些功能从而实现对服务的调用。
-
可以通过 WebSphere DataPower 的扩展元素 <dp:url-open> 调用 Web 服务。典型的用法如清单 1 所示:
清单 1. DataPower 调用外部服务所使用的扩展函数
<dp:url-open http-headers="$vHeaders" target="Resource_URL " response="xml">
<xsl:copy-of select="$vSoapMessage" />
</dp:url-open>
|
在上面的片段中,vHeaders 中可以定义一些 http 头信息,比如 SOAPAction 等,Resource_URL 就是要请求的 Web 服务的地址,而 vSaopMessage 里存放着 Web 服务的请求消息。
-
将信息保存在 WebSphere DataPower 的变量中,供后续使用,典型的用法如清单 2 所示。
清单 2. 将消息保存在 DataPower 的变量中
<xsl:template match="/">
<xsl:variable name="vFee"
select=" //*[local-name()='getFeeResponse']/*[local-name()='fee']"/>
<dp:set-variable name="'var://context/feeResult/fee'"
value="string($vFee)" />
<xsl:copy-of select="."/>
</xsl:template>
|
在清单 2 的片段中,使用了 <dp:set-variable> 将当前的消息作为整体保存至 DatPower 的 context 变量 feeResult/fee 中。WebSphere DataPower 中可以存放多种变量,要详细了解,请参考文献。
接下来就要使用这个扩展函数在来实现服务组装了,WebSphere DataPower 收到客户端的服务请求以后,会经过下列步骤:
-
使用客户端的请求消息构建 FeeService 的请求消息,并请求 FeeService;
-
保存放回消息到环境变量中;
-
再次使用客户端的请求消息构建 DiscountService 的请求消息,并请求 DiscountService;
-
将两次服务调用的结果结合起来,产生实际要扣除的费用值;
-
根据第四步产生的费用,调用 FeeDuctionService 进行实际扣费操作;
-
生成响应消息返回客户端。
在 WebSphere DataPower 的 Policy 编辑器中所看到的视图如下:
图 6. 服务组装 XML Firewall 配置页
点击图 6 红框圈定的浏览按钮进入 Policy 配置页。
图 7. 服务组装 XML Firewall 的 Policy 配置
下图是调用服务 FeeService 的 Transform Action 的配置,其他的配置类似。
图 8. FeeService 的 Transform Action 的配置
Transform 所使用的 invoke_feeservice.xsl 可以在代码下载部分下载。
到此,我们已经介绍完如何实现服务组装,下面我们介绍服务控制的部分。
服务控制
服务控制作用于要控制的所有服务,也就是说,客户端对于所有的服务请求,必须经过这一层,只会有通过了这一层的控制,才能访问或使用后台的服务。我们将通过设计和实现两个部分介绍如何使用 WebSphere DataPower 实现对一组服务的控制。
设计
首先要解决的问题是控制信息放在那里?很容易想到的有两种做法,其一,放在请求消息体中,也就是 SOAP Body 部分;其二,放在消息头中,也就是 SOAP Header 部分。我们推荐使用第二种方法,就像 WS-Security 将相应的安全信息放在 SOAP Header 部分一样,我们也使用 Header 来存放控制信息,清单 2 中 <control:controlInfo> 括起来的部分是控制信息的一个示例。
清单 3. SOAP 消息中存放控制消息示例
<soapenv:Envelope xmlns:soapenv=http://schemas.xmlsoap.org/soap/envelope/
xmlns:control ="http://control.dppaper.com">
< control:controlInfo>
<request>
<serviceID>1000001</serviceID>
<clientID> 0001</clientID>
<usageBegin>090801</usageBegin>
<usageEnd>090810</usageEnd>
<handShake>encrypted_hs_token </handshake>
</request>
</ control:controlInfo>
</soapenv:Header>
<soapenv:Body>
<! — Body of Service Request -- >
</soapenv:Body>
</soapenv:Envelope> |
通常来说 handShake 是在正式服务调用之前完成的,这个握手在客户端和 WebSphere DataPower 之间进行,如果成功握手,则 WebSphere DataPower 会给客户端返回一个加密的令牌信息,即表 2 中的 encrypted_ hs_token,如果不成功,则这个令牌信息为空。
后续的服务调用中,客户端在控制信息部分会把这个 encrypted_hs_token 包含在请求消息的消息头部分。WebSphere DataPower 拿到该令牌后首先对其进行解密,并验证这个令牌是否有效,如果有效,则根据消息头部的其他信息进行控制,如用其他部分进行前面一部分所描述的计费操作等。
整个控制过程如果顺利实行的话,则将服务路由到真实的后台服务。如果失败的话,则向用户返回错误消息。
实现
我们将用一个 XML Firewall 来进行统一的服务控制,控制阶段如果成功的话,则将服务的请求路由到后面的一个 Web Service Proxy(WS-Proxy) 进行服务的路由,WS-Proxy 为这一组业务服务提供了一个统一的虚拟接口,我们可以在 WS-Proxy 中对服务进行路由。路由包括静态路由和动态路由,静态路由根据在 WS-Prox 中注册的服务进行路由,动态路由则需要一个动态的服务注册库(如 IBM 提供的 WSRR)记录服务的元数据信息,从而实现基于消息内容的路由。本文不对此进行展开,若想了解相关信息,请 参考 IBM 红皮书。
现在介绍在 XML Firewall 中实现服务控制,这里包含两个方面的内容。
-
对于第一次握手请求,为客户端生成加密和签名过的令牌 encrypted_and signed_hs_token;
-
对于后续的请求,验证令牌是否正确,并进行服务计费操作。如果验证通过,则将服务路由到 WS-Proxy 进行服务的路由。
握手请求的处理过程如下:
第一步:接受到请求消息后,将请求消息中的控制信息取出来;
第二步:使用这些控制信息,想后台应用服务器发出获取令牌的请求,并等待响应。不过在本文中,由于前文已经演示了如何请求后台的服务,所以这里就在 WebSphere DataPower 中简单返回一个静态的令牌。
第三步:对该令牌进行加密。
第四部:返回客户端。
图 9 显示的就是握手请求控制流的 XML Firewall 的 Policy 配置页面。
图 9. XML Firewall 中握手控制流的配置
下图是打开 Probe 后的测试过程:
图 10. 从 Probe 中看到的消息——输入消息:
图 11. 从 Probe 中看到的消息——返回 token:
图 12. 从 Probe 中看到的消息—— token 加密后:
控制请求的处理过程:
-
接受服务请求,从请求消息中获取控制消息。
-
对加密的令牌进行解密,并验证其是否正确。
-
调用服务计费操作
-
如果成功,则将请求路由到后台的 WS-Proxy 进行服务的路由(请求的是哪个服务,就将请求消息路由到哪个后台服务)。
下图显示了控制流的配置页面。
图 13. XML Firewall 中服务控制的配置
至此,我们已经介绍完了 WebSphere DataPower 上可以实现的两个重要功能:服务组装和服务控制。
注意:在本文的实现中,为了看的清晰,省略了错误处理,相关的知识请参考 WebSphere DataPower 操作手册。
结束语
本文中,我们通过一个场景描述了 WebSphere DataPower 的两个重要的功能,服务组装和服务控制。希望读者能够从中获益。本文中关于服务控制的设计思想是可以借鉴的。此外,如何调用一个外部服务 ? 如何管理消息流中的临时变量?这些都是值得读者好好揣摩的技术点。本文的很多示例代码可以不需要很多修改就可以应用于真实的场景中。
本文所有的结论性申明仅代表个人观点,不代表 IBM 公司的观点。
下载 | 描述 | 名字 | 大小 | 下载方法 |
|---|
| 模拟后台服务的应用,可直接部署到 WAS V6.1的服务器 | DemoWSApp.ear | 14 KB | HTTP |
|---|
| 用于导入到 DataPower 的配置文件 | dp_export.zip | 407 KB | HTTP |
|---|
| 配置中所使用的 xslt 文件 | xslt_samples.rar | 7 KB | HTTP |
|---|
参考资料 学习
获得产品和技术
-
下载 IBM 产品评估版
,并开始使用来自 DB2、Lotus、Rational、Tivoli 和 WebSphere® 的应用程序开发工具和中间件产品。
关于作者  | |  | 马国耀,2007 年毕业于北京大学信息科学技术学院后加入 IBM,在 CDL 的 BPTSE 工作,专门负责战略合作伙伴的 SOA 和 WebSphere 技术和产品的 Enablement 和 Education 相关的工作。有丰富的 SOA 和 WebSphere 产品相关的实施经验。曾在 developerWorks 中文网站发表过2篇文章(DataPower和ESB方面)。 |
对本文的评价
|