27 July 2009
熟悉 BlazeDS 和 Spring 并对 Spring BlazeDS Integration 项目有一定了解将有所帮助。
初级
Spring BlazeDS Integration 项目与面向客户端过滤的全新 Flexible Chimp 项目为全面保护企业 Flex 应用程序提供了一个理想解决方案。
虽然安全性是企业应用程序最重要的方面之一,它同时也可能成为软件开发中最困难的问题。因此,应当在应用程序开发中尽早考虑安全性问题。定义应用程序安全性时,通常使用 AAA(验证、授权与访问控制)范例对如何保护应用程序的各个方面进行分类。某些安全性控件特意经过冗余处理,从而提供双重安全性。
保护 Flex 应用程序时,需要保护许多资源,其中包括用户可以看到哪些数据、用户可以加载哪些模块或用户可以访问哪些屏幕。从更细微的安全性角度而言,您可能需要限制用户读取(但不能写入)某些数据或隐藏用户界面中的特定组件。除了提供 BlazeDS 与通过 Spring 实施的 Java 后端之间的集成外,Spring BlazeDS Integration 项目还提供一些功能,用于保护 Flex 应用程序使用的 Java 服务,借助 Spring Security 提供了一个全方位的解决方案。这个解决方案允许您从 BlazeDS 和 Spring Bean 中定义的终点的服务和方法级别定义安全性。
Flexible Chimp 是 Gorilla Logic 发起的一个新项目,它为 Adobe Flex 和 AIR 应用程序提供了基于权限的过滤。可以根据用户角色保护个别组件。Chimp 通过基于权限的组件过滤提供用户界面的客户端安全性。应用程序将元数据添加到 Flex UIComponent 类的实例中,即可实施 Chimp。Chimp 将根据元数据完全删除组件、启用它们、禁用它们或更新它们的可见性。有关更多信息,请参阅 Flexible Chimp 项目网站。
企业开发人员应当熟悉安全性的三个 A:
这一部分提供了如何使用 Spring BlazeDS Integration 项目配置 Java 服务器的基本概述。有关深入参考资料,请参阅 Spring BlazeDS Integration 项目页或 DZone's Refcard。
为了保护与服务器的通信,Spring BlazeDS Integration 项目采用一种基于 Spring Security 的验证和授权流程。这个流程将 Spring Security 与 BlazeDS 安全性流程结合在一起。
要配置项目的服务器端,您需要编辑 web.xml 文件。在这个文件中,添加一个用于定义 Spring Security 上下文的上下文配置文件:
<!-- The front controller of this Spring Web application, responsible for handling all application requests -->
<servlet>
<servlet-name>sodablaze</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/config/security-context.xml
/WEB-INF/config/web-application-config.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
并在 web.xml中,记下 URL 映射,确保它与为 BlazeDS 定义的通道相符。在这个范例中,映射到 MessageBroker URL:
<!-- Map all *.spring requests to the DispatcherServlet for handling -->
<servlet-mapping>
<servlet-name>sodablaze</servlet-name>
<url-pattern>/gorilla/*</url-pattern>
</servlet-mapping>
在 Flex 配置文件中, services.xml,确保 URL 定义还映射到 MessageBroker URL:
<channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
<endpoint url="http://{server.name}:{server.port}/{context.root}/gorilla/messagebroker/amf"
class="flex.messaging.endpoints.AMFEndpoint"/>
</channel-definition>
<channel-definition id="my-secure-amf" class="mx.messaging.channels.SecureAMFChannel">
<endpoint url="https://{server.name}:{server.port}/{context.root}/gorillamessagebroker/amfsecure"
class="flex.messaging.endpoints.SecureAMFEndpoint"/>
<properties>
<add-no-cache-headers>false</add-no-cache-headers>
</properties>
</channel-definition>
现在已定义通道并设置调度 servlet,您可以定义安全性上下文,web.xml 文件中引用到它。 security-context.xml 文件定义了应用程序的用户和角色。以下是验证提供程序的示例配置:
<authentication-provider>
<user-service>
<user name="ryan" password="utah" authorities="ROLE_USER, ROLE_ADMIN" />
<user name="jon" password="colorado" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
远程服务在应用程序上下文文件 web-application-config.xml中作为 Spring Bean 进行声明。这个范例文件出于示例目的,将同一个类定义为两个单独 bean。第一个 bean 是 sodaService,第二个 bean 是 securedSodaService。第二个 bean 通过定义可以访问远程服务的角色来保护服务:
<!-- A secured version of productService -->
<bean id="securedSodaService" class="com.gorillalogic.sodaBank.SodaService" >
<flex:remoting-destination />
<security:intercept-methods>
<security:protect method="get*" access="ROLE_USER" />
</security:intercept-methods>
</bean>
Spring 和 BlazeDS 的安全性可以很简单,也可以像您要求的那样复杂。您可以按角色保护整个 Spring bean,或者通过定义公开的方法以及可以访问这些方法的人员应用更细微的访问控制。
全新 Spring BlazeDS Integration 项目可以帮助您轻松、直接地将 Spring 与 BlazeDS 结合在一起,使您能够轻松使用 Spring Security 为服务添加安全性。
您已回顾 Spring 和 BlazeDS 集成,现在可以借助 Flexible Chimp 项目保护客户端,从而增强服务器端安全性。
使用 Chimp 保护 Flex 客户端之前,您应当保护 Java 服务器。本文将说明如何使用 Spring 配置服务器安全性,但这一部分中讨论的 Chimp 和方法可用于任何安全服务器。无论您如何实施服务器,问题的关键是服务器端的服务和数据得到真正的保护,因为这才是实施安全性的核心所在。在这一部分中,我将说明如何通过 ChannelSet 验证 Flex 中的用户,然后讨论根据用户的角色或权限过滤用户可以看到的内容。Chimp 十分适合过滤客户端的用户界面组件,因为只需向 MXML 及 ActionScript 源代码添加元数据,就可以保护视图。Chimp 主页对该项目的描述如下:
“Chimp 是一个面向 Adobe Flex 和 AIR、基于权限的过滤组件。应用程序将元数据添加到 Flex UIComponent 中,即可实施 Chimp。Chimp 将根据元数据完全删除组件、启用/禁用它们、更新可见性。”
只有验证用户后,才能使用 Chimp 保护 Flex 中的用户界面组件。在 Flex 中,可以通过 ChannelSet 验证访问 BlazeDS 服务的用户。在以下 Flex 验证代码中,我们创建一个 userService 远程对象。假设 BlazeDS 中已配置 userService。在本例中,该操作通过 BlazeDS/Spring 配置完成。这个示例十分简明。用户名和密码参数来自一个登录表单并传递给 authenticate 函数。成功登录后,将调用 loginResultEvent 处理函数,随后可以调用登录后逻辑。
<mx:AMFChannel id="myamf" uri="http://localhost:8080/spring/messagebroker/amf"/>
<mx:ChannelSet id="channelSet" channels="{[myamf]}"/>
<mx:RemoteObject id="userService" destination="userService" showBusyCursor="true"
channelSet="{channelSet}"/>
<mx:Script>
<![CDATA[
protected function authenticate(username:String, password:String) : void {
var token:AsyncToken = userService.channelSet.login(username, password);
token.addResponder(new ItemResponder(loginResultEvent, loginFaultEvent));
}
private function loginResultEvent(event:ResultEvent, token:AsyncToken):void {
//DO post login stuff
}
]]>
</mx:Script>
在稍后的加载用户与权限部分中我们将讨论登录后逻辑。
使用 Chimp 时,我们首先将 SWC 文件添加到您的 Flex 应用程序。首先,下载 chimp.swc 文件(从 Google Code)。在标准 Flex Builder 项目中,按照这些步骤将文件添加到项目库中:
然后,您需要更新项目以保留 Chimp 使用的元数据。在标准 Flex Builder 项目中,按照这些步骤告诉 Flex 编译器保留元数据:
现在 Chimp 已安装到 Flex 项目中,此时可以将 Chimp 项目加载到 Flex 应用程序中。请务必在将应用程序组件添加到应用程序之前加载 Chimp,因为 Chimp 要使用 Flex 应用程序系统管理器的 ADDED_TO_STAGE 事件标记要保护的组件。您在 Swiz 框架等其他开放源代码 Flex 库中也会看到类似的系统管理器使用方法。
在用户界面组件之前加载 Chimp 最简单的方法是使用应用程序的 Flex preinitialize 事件。在生产应用程序中,您不是依赖于 preinitialize 事件,而是可能使用某种视图状态防止添加组件,直至验证用户或加载角色后。
在 Flex 应用程序中加载 Chimp 很简单:
private function preintializeHandler(event:Event):void {
Chimp.load(null);
}
在以上代码中,Chimp 加载到预初始化应用程序事件处理函数中。为角色传入一个 null,因为在本例中尚未加载它们。此时加载 Chimp 使它能找到标注有需要保护的 Chimp 元数据的组件。
Chimp 此时被添加并加载到 Flex 应用程序中。然后,需要从 Spring 加载权限,将使用它们来确定用户可以看到哪些内容。Chimp 需要一般权限字符串。它们可以是角色、权限或可以作为字符串返回的任何内容。本文将使用 Spring GrantedAuthorities 对象获取要用于 Flex 应用程序中的用户权限。以下代码定义了 UserIdentity 对象,将使用这个简单的 Java 类返回安全性信息。
public class UserIdentity {
private String username;
private List<String> roles;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public List<String> getRoles() {
return roles;
}
public void setRoles(List<String> roles) {
this.roles = roles;
}
}
此处,根据 Spring SecurityContextHolder 汇编 UserIdentity 对象:
public UserIdentity getUserIdentity() {
UserIdentity ui = new UserIdentity();
//set user name
ui.setUsername(userDao.getUser(SecurityContextHolder.getContext().getAuthentication().getName()));
//set string permissions
List<String> perms = new ArrayList<String>();
GrantedAuthority[] gas = SecurityContextHolder.getContext().getAuthentication().getAuthorities();
for(int i=0; i < gas.length; i++) {
perms.add(gas[i].getAuthority());
}
ui.setRoles(perms);
//return user identity object
return ui;
}
在本例中,Flex 应用程序将在成功验证用户后,调用 getUserIdentity() 方法:
public var userService:RemoteObject;
private function loginResultEvent(event:ResultEvent, token:AsyncToken):void {
var userIdentityToken:AsyncToken = userService.getUserIdentity();
userIdentityToken.addResponder(new ItemResponder(userIdentityEvent, faultEvent));
}
private function userIdentityEvent(event:ResultEvent, token:AsyncToken):void {
//set user permissions on Chimp
Chimp.updatePerms(event.result.roles);
}
成功验证用户后,将加载用户身份信息并在 Chimp 库的实例上更新权限。这些信息与元数据一起用于限制用户在 Flex 用户界面中可以看到的内容。
此时,Chimp 已安装并加载到应用程序中,并且服务器已经向它提供角色。我们现在要向 Flex 代码添加元数据,以限制用户在用户界面中可以看到的内容和执行的操作。以下是一个受 Chimp 保护的元数据的用例:
<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="/2006/mxml">
<mx:Metadata>
[Protected(permissions="admin",notInPermissionAction="removeChild",componentId="box2")]
[Protected(permissions="admin",notInPermissionAction="removeFromLayout",componentId="p2")]
[Protected(permissions="admin",inPermissionAction="visible",componentId="adminButton")]
[Protected(permissions="user",inPermissionAction="enable",componentId="updateButton")]
</mx:Metadata>
<mx:Button id="adminButton" label="Admin Button" visible="false" />
<mx:Button id="updateButton" label="Update Button" enabled="false" />
<mx:HBox>
<mx:Panel id="p1" title="Panel 1" backgroundColor="#FF0000"/>
<mx:Panel id="p2" title="Panel 2" backgroundColor="#00FF00"/>
<mx:Panel id="p3" title="Panel 3" backgroundColor="#0000FF"/>
</mx:HBox>
<mx:TabNavigator id="tabNav" width="300" height="300">
<mx:VBox id="box1" width="100%" height="100%" label="Tab One">
<mx:Text text="first tab" />
</mx:VBox>
<mx:VBox id="box2" width="100%" height="100%" label="Tab Two">
<mx:Text text="second tab" />
</mx:VBox>
<mx:VBox id="box3" width="100%" height="100%" label="Tab Three">
<mx:Text text="third tab" />
</mx:VBox>
</mx:TabNavigator>
</mx:VBox>
仔细观察 Protected 注释部分。
如果找不到“admin”权限,下一行将删除选项卡导航器中的第二个框。这里使用 removeChild,因为 removeFromLayout 无法用于 TabNavigator 组件。如果 removeFromLayout 选项有效,则最好使用它,因为它的攻击性较弱,并且如果稍后提供“admin”权限,它的行为可预测性更高。
[Protected(permissions="admin",notInPermissionAction="removeChild",componentId="box2")]
对于下一行,如果找不到“admin”权限,将从布局中删除 HBox 中的第二个面板,它将不再可见:
[Protected(permissions="admin",notInPermissionAction="removeFromLayout",componentId="p2")]
以下,如果用户拥有“admin”权限,将显示 adminButton:
[Protected(permissions="admin",inPermissionAction="visible",componentId="adminButton")]
最终,如果用户拥有“user”权限,将启用 updateButton:
[Protected(permissions="user",inPermissionAction="enable",componentId="updateButton")]
受保护注释的使用很简单。它具有以下属性:
permissions:permissions 属性需要一串以逗点分隔、用于受保护操作的字符串权限。componentId:这个 componentId 是要保护的组件的字符串名。对于当前组件,可以省略它或将它设置为“this”。要保护子代,请将 componentId 设置为组件的“id”字符串。notInPermissionAction:如果用户没有任何权限,则调用 notInPermissionAction(使用“this”或“inPermissionAction”-不能同时使用)。inPermissionAction:如果用户拥有任何权限,则调用 inPermissionAction(使用“this”或“notInPermissionAction”-不能同时使用)。notInPermissionAction 和 inPermissionAction 属性调用目标组件上的操作。它们可以使用以下值:
removeChild:通过调用“comp.parent.removeChild ”完全删除组件。removeFromLayout:使用 includeInLayout 属性删除组件。invisible:将 compl.visible 属性设置为 false。visible:将 comp.visible 属性设置为 true。disable:将 comp.enable 属性设置为 false。enable:将 comp.enable 属性设置为 true。如您所见,Chimp 库在 Flex 应用程序中的使用很简单。安装并加载到应用程序中后,它为管理视图组件的权限提供了一种简单、优雅的方式。
通过结合使用 Spring BlazeDS Integration 和 Flexible Chimp 项目,您可以为应用程序提供全方位的安全性。Spring BlazeDS 项目简化了 Spring Security 与 BlazeDS Security 的集成,为定义用户和角色的管理方式以及如何为应用程序提供验证赋予了灵活性。在前端使用 Flexible Chimp 提供了细致的用户界面安全性。这种项目组合保护了验证、授权和访问控制的各个方面。
有关 Spring BlazeDS Integration 项目的更多信息,请参阅项目主页或演示如何实施项目的 DZone's Refcard。