级别: 中级 李 凌 (liling@cn.ibm.com), 软件架构师, IBM
2009 年 6 月 29 日 服务网关模式是 SOA 中实现松散耦合和访问安全的重要设计模式。本文详细介绍了在 WebSphere Integration Developer(WID)6.2 开发环境中实现动态服务网关模式的方法。在示例应用程序中,读者可以看到如何开发支持动态网关模式的中介流,并添加认证、授权、审计(AAA)等重要的功能,进一步强化服务网关在整个 SOA 架构中的重要作用。通过本文,读者还可以了解到 WebSphere Enterprise Service Bus(WESB)最新 6.2 版本的新特性。
SOA 的网关模式
在 SOA 架构设计中通常会引入服务网关这样一个软硬件实现,以作为企业内部服务的集中管控点。
服务网关可以完成下列核心功能:
-
服务请求的路由,包括静态路由或动态路由,从而实现服务虚拟化;
-
在不同的传输协议之间映射服务请求和响应,或在不同的数据格式、接口规范之间转换服务请求和响应;
-
实现服务请求的访问控制(认证和授权)及审计。
这种融入了服务网关的 SOA 设计模式称为网关模式。在此模式中,服务网关作为服务生产者和消费者之间的服务中介,替换了传统实现模式中生产者和消费者直接交互的方式,如图 1 所示。网关模式体现了 SOA 的一些重要设计原则,例如:将服务消费者与服务的具体实现脱耦;将服务交互与其所依赖的实现技术相分离;集中治理企业内部的各个服务等等。
图 1. 网关模式
WebSphere ESB 对网关模式的支持
WebSphere Enterprise Service Bus(简称 WebSphere ESB 或 WESB)是 IBM 为企业级用户提供 Web 服务连通性和 JMS 消息传递的软件产品。它提供了基于标准的连接和集成解决方案,允许用户只需少量编程便能实现消息的格式转换、协议转换、寻址和路由,从而实现与任何 JMS 和 HTTP 应用程序的轻松集成。
当前 WebSphere ESB 的最新版本是 V6.2,该版本新加入了策略驱动的连接性支持(详见参考资源中的“中介策略模式”),可以从 IBM WebSphere Service Registry and Repository(简称 WSRR)中提取策略文件以驱动消息的处理;新增了 Type Filter、Data Handler 和 Header Setter 等中介原语,可以更便捷地构建中介流;此外,还强化了对最新 Web 服务标准的支持,包括 SOAP 1.2、JAX-WS 2.1 等等,可以构建新一代基于策略的 Web 服务。
WebSphere ESB 使用中介流(Mediation Flow)实现网关模式。在此模式中,请求消息首先被传入到中介流的输入节点,然后经过一系列中介流原语(Mediation Primitive)的处理之后,路由到目标服务;同样,响应消息也可以经过中介流的处理再路由到服务调用者。
在先前版本的 WESB 中,中介流只能实现静态网关模式,典型的实现方式是使用 Message Filter 中介原语根据事先定义的路由规则进行静态路由,如图 2 所示。静态网关模式中,服务请求到目标服务的映射是静态绑定的,每次变更都需要修改中介流模块,灵活性比较差。
图 2. 静态网关模式
WebSphere ESB V6.2 通过使用新的 Data Handler 和 Endpoint Lookup 中介原语来支持动态服务网关。Gateway Text Data Handler 和 Service Gateway Function Selector 使得网关仅使用一个统一的接口就能接入不同的服务。不同于在中介流中的硬编码分支和逻辑,Endpoint Lookup 中介原语使用外部的服务存储库来动态查找服务端点,从而实现服务信息的运行时动态绑定,如图 3 所示。外部的服务存储库可以是专业的 WSRR、普通的关系型数据库、甚至是简单的文件。如果某个服务的信息发生了更改,变更工作将在外部存储库中完成,不需要修改 WESB 上的中介流和网关接口,从而使得此实现成为动态的。
此外,由于采用的新的数据绑定方式,基于 WebSphere ESB V6.2 实现的服务网关可以使用 SOAP 1.2/HTTP、SOAP 1.1/HTTP、HTTP、JMS 或 MQ 作为传输协议。
图 3. 动态网关模式
本文的后续章节以 SOAP1.2 传输协议为例,详细介绍了动态服务网关的实现方式,有效地改进了 SOA 应用程序的运行时灵活性和连通性;并在该服务网关上实现了认证、授权和审计(AAA)功能,进一步强化服务网关在整个 SOA 架构中的重要作用。
构建动态服务网关框架
IBM WebSphere Integration Developer(简称 WID)是开发、调试和测试 SCA(Service Component Architecture)和中介流的集成开发环境。
本节将以 WID 6.2 为开发环境构建支持 SOAP1.2 协议的动态服务网关框架。这个动态网关可以根据请求消息中包含的服务名称到 WSRR 上搜索该服务的服务端点地址(Endpoint address),从而在运行时动态决定这个请求所要发送到的目标地址。服务名称信息将被包含在请求消息的 HTTP URL 中,例如 http://gateway_address/gateway?ServiceName=MyService。中介流可以从该 URL 中解析出服务名称为 MyService,进而查询 WSRR 得到该服务的真实地址为 http://test.com/MyService,最后把请求转发到目标服务。如图 4 所示。
图 4. 动态路由
实际上,搜索条件可以不局限于服务名称,也可以是服务版本、命名空间或任何自定义条件,这些条件还可以组合使用。考虑到性能因素,动态网关通常根据服务请求的上下文信息进行消息路由,而不会使用整个请求内容。在本例中,路由条件“服务名称”被放在 HTTP 请求头的 URL 后缀中,就是为了尽可能快地加速路由的处理过程,减少性能损耗。
首先,在 WID 中启动 Service Gateway 向导,File -> New -> Service Gateway,指定项目名称为 ServiceGateway,如图 5 所示,点击 Next 继续。
图 5. 指定项目名称
选择 Gateway 的类型为 Dynamic,以便创建一个动态网关,如图 6 所示。点击 Next。
图 6. 指定网关类型
在随后出现的“选择服务提供者”对话框中需要指定动态网关所使用的服务存储库类型,如图 7 所示,它可以是 WSRR、普通的数据库、或者是自己实现特定的处理逻辑等方式。这里选择 WSRR。其次,还可以指定是否进行服务请求和响应消息的记录,这里选择不记录,本文将在后续章节中介绍如何添加自定义的审计功能。点击 Next 继续。
图 7. 指定服务存储库
在图 8 所示菜单里选择网关使用的传输协议为 Web Service SOAP1.2/HTTP,表示网关所支持的服务类型是 JAX-WS Web 服务。SOAP1.1/HTTP 协议的网关适合处理 JAX-RPC Web 服务;HTTP 协议的网关适合处理普通的 Web 应用或者是 XML over HTTP 类型的 Web 服务;JMS 和 MQ 协议的网关则适合处理消息类型的应用。点击 Finish 完成创建。
图 8. 指定传输协议
切换到 Business Integration 视图,可以看到名为 ServiceGateway 的中介处理模块(Mediation Module)已经被创建。打开其中的装配图(图 9),可以看到图中包含 1 个 Export 组件,用于暴露网关所在的 JAX-WS 服务;1 个中介流组件,用于实现消息流转逻辑;和 1 个 Import 组件,用于调用后端的 JAX-WS 服务。
图 9. 装配图
Import 和 Export 组件均使用了 ServiceGateway 接口,该接口包含 2 个处理方法,如图 10 所示,其中 requestOnly 方法用于处理 One-way 方式的服务调用;requestResponse 方法用于处理 Request-and-Response 方式的服务调用,后续文章仅以 Request-and-Response 方式为例实现动态网关。可以看到,这两个方法的参数类型都是任意类型(anyType),这是因为网关要处理各种类型的服务请求。
图 10. 网关接口
双击 ServiceGateway 中介流模块,打开其具体实现,选中其中的 requestResponse 中介流,如图 11 所示。
图 11. Request Response 中介流
在 requestResponse 中介流中,选中 RouteMessage(Endpoint Lookup)原语,如图 12 所示,该原语以 WSRR 作为服务存储库,负责根据特定的条件(例如:服务名称)到 WSRR 中搜索指定服务的端点地址。
图 12. Endpoint Lookup 原语
为了实现动态网关的功能,在其 Properties -> Advanced -> User Properties 界面中添加端点搜索条件为 xPath 表达式 s
ubstring-after(/headers/HTTPHeader/control/URL ,"?ServiceName=" ),如图 13 所示。该表达式用于从请求的 HTTP URL 参数中截取服务名称信息。
图 13. 搜索条件
由于本示例的动态网关使用了 WSRR 作为服务存储库,因此需要在测试 WESB/WPS 服务器上添加对 WSRR 的定义,并确保使用 6.2 或以上版本的 WSRR SOAP 接口,以便测试服务器可以正确访问 WSRR 服务存储库。同时,还需要将目标服务(Echo Web 服务)的 WSDL 和 XSD 文件导入到 WSRR 中,这两个文件可以从 EchoWS 工程中获取,测试服务(EchoWS)及其客户端(EchoClient)工程可从文章末尾的链接下载。
除了 WSRR 以外,动态网关还可以使用普通的数据库或者文件作为服务的存储库,使其在与第三方系统集成的时候具有很大的灵活性。
测试网关框架
为了测试网关框架的有效性,首先在 WID 中导入 Echo Web 服务的测试客户端 EchoClient 工程。该客户端能够向 Echo 服务发送一个“Hello world!”字符串,并显示调用的结果。由于要通过 Service Gateway 动态调用 Echo 服务,因此需要修改客户端发送 SOAP 请求的目的地址为动态网关的地址。打开 EchoClient -> META-INF -> wsdl -> EchoService.wsdl 文件,确保其中的 SOAP12 Address 元素如清单 1 所示。
清单 1. 访问地址
<service name="EchoService">
<port binding="tns:EchoPortBinding" name="EchoPort">
<soap12:address location=
"http://localhost:9080/ServiceGatewayWeb/sca/ServiceGatewayExport?ServiceName=Echo"/>
<!--<soap12:address location="http://localhost:9080/EchoWS/EchoService"/>-->
</port>
</service>
|
然后,将 ServiceGateway 模块发布到 WID 自带的 WESB 测试服务器上,并确保该模块被正确启动。最后,以 WebSphere Application Server V6.1 Application Client 的方式运行 EchoClient 工程,观察 Console 窗口,可以发现调用结果如清单 2 所示,说明网关正确地将服务请求路由到了目标服务,并返回了调用结果。
清单 2. 运行结果
Service invoking...
Service result: Hello world!
|
实现访问控制和审计
对于一个服务网关而言,它除了具备基本的服务请求的动态路由功能外,还需要具备认证、授权和审计(Authentication Authorization and Audit, AAA)功能,从而确保网关服务的安全性。本节将详细介绍这些功能在 Service Gateway 上的实现。
认证
认证(Authentication)是指对用户身份信息的鉴别,并仅对拥有合法身份的用户予以放行,是实现访问控制的基础。实现身份认证的方法有很多种,常见的包括用户名和口令认证、证书认证等。本节将介绍使用 HTTP Basic Authentication 实现身份认证的方法。
首先,在 Service Gateway 工程上点击右键,选择 Open Deployment Editor,打开中介流模块部署描述符。然后切换到 Exports 选项卡,在该选项卡中添加一个 Security Role,名称为 Authenticated。接着,为这个 Role 添加一个安全约束(Security Constraints),该约束定义了授权角色 Authenticated 所允许访问的 Web 资源集合,如图 14 所示。
图 14. Export 设置
接着,还需要为这个中介流模块配置允许访问的用户。切换到部署描述符的 Module 选项卡,在其中的 Security 选项点击 Gather 按钮,Authenticated 角色将自动被收集到 Security Roles 列表中;配置该角色所对应的 WebSphere Bindings 为 All authenticated users,如图 15 所示。
图 15. Security 设置
最后,保存并关闭模块部署描述符。以上配置完成了服务网关的认证功能,当未认证的用户访问服务网关时,将收到“HTTP 401 Unauthorized”异常信息。认证用户需要被添加到服务网关所在的 WESB 使用的用户注册库中(User Registry)。
授权
授权(Authorization)是指对已经通过身份验证的用户进行权限的赋予。被授权的用户只能执行自身权限所限定的行为。通过授权,可以实现多层次细粒度的访问控制。
本例中实现的授权模型,如图 16 所示,用户被映射到用户组(角色),用户组(角色)关联到授权访问的服务资源。该模型定义了哪些用户被允许访问哪些服务。这个授权模型以关系型数据库 Schema 的方式实例化,每个模型实体代表一个数据库表。这里以 DB2 为实现数据库,并在 WESB 测试服务器上配置了相应的 JDBC Provider 和 Data Source(jdbc/authorization)。
图 16. 授权模型
要实现网关的访问授权,首先在 WID 中打开 Service Gateway 工程,在其 Data Types 中添加一个 Business Object,命名为 RouteInfo,该 BO 包含了一个 String 类型的 URL 变量,用于保存从 HTTP 头中读取的请求 URL 信息,该信息包含了目标服务的名称。
接着打开 Service Gateway 中介流,为中介流添加两个消息处理原语,分别是 HTTP Header Setter 和 Custom Mediation,如图 17 所示。
图 17. 授权原语
打开其中 Get Service Name 原语的属性窗口,添加处理逻辑,如图 18 所示。它负责从服务请求的 HTTP 头中获取 URL,并拷贝到 SMO(Service Message Object)的变量 /context/transient/url 中。
图 18. 获取 HTTP URL
其次,在 Authorization 原语中添加访问授权处理逻辑,代码片段如清单 3 所示。这段代码首先从运行时上下文中获取已认证用户的登录信息,然后从 SMO 的 /context/transient/url 变量中获取该用户要访问的服务名称,最后调用 isAuthorized() 方法进行授权判断。
清单 3. 执行授权
String uid = "";
Context ctx = ContextManager.getContext();
Set<Principal> set = ctx.getRunAsSubject().getPrincipals();
for (Principal principal : set) {
uid = principal.getName();
uid = uid.substring(uid.lastIndexOf('/') + 1);
}
commonj.sdo.DataObject _smo = (commonj.sdo.DataObject)smo;
String url = _smo.getDataObject("context").getDataObject("transient").getString("url");
String serviceName=url.substring(url.indexOf("=")+1);
boolean isAuthorized=false;
isAuthorized=DAO.isAuthorized(uid,serviceName);
if(!isAuthorized)
throw new ServiceBusinessException("Authorization failed!");
out.fire(_smo);
|
其中 DAO.isAuthorized() 方法访问授权数据库,并判断当前用户是否具有权限访问指定服务;如果授权通过则返回 True,否则抛出运行时异常“Authorization failed!”。关键代码片段如清单 4 所示。
清单 4. 授权方法的实现
public static DataSource ds = null;
public static Connection getDSConn() throws Exception {
if (ds == null) {
InitialContext nctx = new InitialContext();
ds = (DataSource) javax.rmi.PortableRemoteObject.narrow(nctx
.lookup("jdbc/authorization"), DataSource.class);
}
return ds.getConnection();
}
public static boolean isAuthorized(String user, String service) {
boolean result = false;
Connection conn = getDSConn();
PreparedStatement pStQuery = conn
.prepareStatement("select * from user, group, service where user.name='"
+ user + "' and service.name='" + service + "'");
ResultSet rs = pStQuery.executeQuery();
while (rs.next())
result = true;
pStQuery.close();
conn.close();
return result;
}
|
除了上述的实现以外,认证和授权的功能还需要底层服务器的支持,即服务网关所在的 WESB 服务器必须启用全局安全性(Global Security)以及应用程序安全性(Java EE Security)。
审计
审计是指对特定行为的记录,记录的内容通常包括行为的主体、行为的内容、行为发生的时间等等。
本节将介绍如何为服务网关添加服务请求和响应的审计功能。在消息中介流中可以方便地实现整个消息或者部分消息的审计,实现方式也有很多种,例如调用外部的审计服务将消息存入独立于网关之外的审计系统;或者直接将消息写入本地的文件或数据库系统。本节以消息日志原语为例实现消息的审计。
首先,在服务请求的中介流中添加一个消息记录原语(Message Logger Primitive),如图 19 所示。
图 19. 审计原语
默认情况下,该原语将消息的内容(Body)以 XML 的形式记录到指定的 JDBC 数据源中(jdbc/mediation/messageLog),在 WID 测试环境中,该数据源对应 WPS 内嵌的 Derby 数据库,数据库的 Schema 文件可以在 {Server_Install_Path}/dbscripts/EsbLoggerMediation 中找到。所记录的消息内容包括时间戳、消息 ID、中介原语名称、模块名称、消息对象(SMO)和对象的版本信息。可以在该原语的 Properties -> Details 菜单中改变这些设置。
同时,消息记录原语还支持自定义消息记录的格式和形式,例如写入到文本文件或操作系统日志。可以通过继承 Handler、Formatter 和 Filter 类来实现自定义审计,这些类是 Java 规范中的标准实现。
最后,可以用同样的方法在服务响应中介流中添加审计功能。
测试
测试之前首先确保测试服务器 WESB 与 WSRR 和授权数据库连接正常,再者确保 WESB 服务器所使用的 User Registry 中存在 Admin 和 User 这两个测试用户;并在授权数据库中添加如表 1 所示的授权信息。
表
1.
授权信息
|
User
|
Group
|
Service
| |
Admin
|
Administrators
|
Echo
| |
User
|
Users
|
Echo1
|
然后,打开测试客户端 Echo Client 的 Main 类,确保其中的用户名和密码信息为“Admin”。最后运行 Echo Client,发现调用成功,检查服务器日志可以得到以下运行结果。
清单 5. 授权结果
[4/20/09 20:42:49:375 CST] 0000005f SystemOut O User: admin
[4/20/09 20:42:49:375 CST] 0000005f SystemOut O Service Name: Echo
[4/20/09 20:42:49:375 CST] 0000005f SystemOut O Perform authorization...
[4/20/09 20:42:49:468 CST] 0000005f SystemOut O Authorization result: true
|
同时消息审计所使用的数据库表中会发现类似下面这条信息的记录。
29/04/09 21:11, 3E42W9K6-1209, Audit, Service Gateway, {Message Body}, 1
|
如果使用 User 用户来发起调用,虽然该用户在 User Registry 中存在,可以通过认证,但由于他未被授权访问 Echo 这个服务,因此会收到“Authorization failed!”运行时异常;如果使用未在 User Registry 中注册的用户或者已注册但未提供正确的口令,那么会收到认证失败的异常。
总结
服务网关模式作为 SOA 架构设计中常用的设计模式,具有脱耦服务消费者和服务提供者、集中管控和治理服务的优点。WebSphere ESB V6.2 提供了对动态网关模式的支持,并且支持包括 SOAP1.2/HTTP、SOAP1.1/HTTP、HTTP、JMS 和 MQ 在内的各种传输协议。本文以 SOAP1.2/HTTP 协议为例,构建了支持 JAX-WS 服务的动态服务网关。动态服务网关所需要集成的服务存储库可以是工业级标准的 WSRR,也可以是简单的关系型数据库。此外,本文还介绍了在动态服务网关上实现认证、授权和审计的方法,进一步强化了服务网关在整个 SOA 架构中的重要作用。
下载 | 描述 | 名字 | 大小 | 下载方法 |
|---|
| 本文代码示例 | TestSuit.zip | 26 KB | HTTP |
|---|
参考资料 学习
获得产品和技术
-
下载 IBM 产品评估版,获得来自 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere® 的应用程序开发工具和中间件产品。
关于作者  | |  | 李凌,IBM 中国软件开发中心软件架构师,主要负责 WebSphere 相关产品的咨询、培训和实施工作;从2007年以来主要从事 SOA(Governance)解决方案咨询与实施工作;在 Web 服务、信息安全和 IP Multimedia Subsystem 领域有丰富的实践经验。 |
对本文的评价
|