在Google appegine上部署BlazeDS和Spring程序(二)
作者:陈省
接着上篇文章,这次我们要添加Spring的安全认证功能,首先在\WEB-INF\config\web-application-security.xml文件中定义认证Provider,
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.1.xsd">
<http auto-config="true" session-fixation-protection="none"/>
<authentication-provider>
<user-service>
<user name="admin" password="admin" authorities="ROLE_USER, ROLE_ADMIN" />
<user name="guest" password="guest" authorities="ROLE_GUEST" />
</user-service>
</authentication-provider>
</beans:beans>
接下来,对于UserService添加认证定义
<bean id="UserService" class="com.sharpplus.UserService" >
<flex:remoting-destination />
<security:intercept-methods>
<security:protect method="get*" access="ROLE_USER" />
</security:intercept-methods>
</bean>
注意还需要指定MessageBroker为基于安全认证的Broker
<flex:message-broker>
<flex:secured />
</flex:message-broker>
否则,运行时总是无法正确认证。
接下来,修改客户端代码,添加登录用户和注销的处理。
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
applicationComplete="applicationCompleteHandler()"
>
<mx:Script>
<![CDATA[
import mx.rpc.AsyncResponder;
import mx.rpc.AsyncToken;
import mx.messaging.events.ChannelFaultEvent;
import mx.messaging.events.ChannelEvent;
import mx.messaging.ChannelSet;
import mx.messaging.channels.AMFChannel;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.controls.Alert;
import mx.messaging.config.ServerConfig;
private var _channelSet:ChannelSet= ServerConfig.getChannelSet("my-amf");
private function onClick():void{
ro.getUser.addEventListener(ResultEvent.RESULT, onResult);
ro.getUser();
}
private function onResult(event:ResultEvent):void{
var s:String=event.result as String;
Alert.show(s);
}
private function applicationCompleteHandler():void
{
// var channel:AMFChannel = new AMFChannel("my-amf", "http://localhost:8400/WebBoxshotMaker/messagebroker/amf");
// _channelSet = new ChannelSet();
// _channelSet.addChannel(channel);
ro.channelSet = _channelSet;
ro.channelSet.addEventListener(ChannelEvent.CONNECT, _onChannelConnect);
ro.channelSet.addEventListener(ChannelEvent.DISCONNECT, _onChannelDisconnect);
ro.channelSet.addEventListener(ChannelFaultEvent.FAULT, _onChannelFault);
}
private function _onChannelConnect(event:ChannelEvent):void {
Alert.show("Channel " + event.channel.id + " connected");
}
private function _onChannelDisconnect(event:ChannelEvent):void {
Alert.show("Channel " + event.channel.id + " disconnected");
}
private function _onChannelFault(event:ChannelFaultEvent):void {
Alert.show("Channel " + event.channel.id + " faulted. " + event.faultString);
}
private function faultHandler(event:FaultEvent):void
{
Alert.show(event.fault.faultString, "Error accessing RemoteObject");
}
private function login():void
{
// ro.channelSet.login(userId.text, password.text);
var token:AsyncToken = ro.channelSet.login(userId.text, password.text);
token.addResponder(new AsyncResponder(function(result:Object, token:Object):void {
Alert.show("Login successful");
}, function(result:Object, token:Object):void {
Alert.show("Login failed");
}));
}
private function logout():void
{
// ro.channelSet.logout();
var token:AsyncToken = ro.channelSet.logout();
token.addResponder(new AsyncResponder(function(result:Object, token:Object):void {
Alert.show("Logout successful");
}, function(result:Object, token:Object):void {
Alert.show("Logout failed");
}));
}
]]>
</mx:Script>
<mx:RemoteObject id="ro" destination="UserService" fault="faultHandler(event)"/>
<mx:Form>
<mx:FormItem label="User Id">
<mx:TextInput id="userId"/>
</mx:FormItem>
<mx:FormItem label="Password">
<mx:TextInput id="password" displayAsPassword="true"/>
</mx:FormItem>
<mx:FormItem direction="horizontal">
<mx:Button label="Login" click="login()"/>
<mx:Button label="Logout" click="logout()"/>
</mx:FormItem>
</mx:Form>
<mx:Button x="257" y="193" label="Hellow BlazeDS" click="onClick()"/>
</mx:Application>
这次运行程序时,如果不登录为admin用户时,按下Hello BlazeDS按钮,会报访问权限的异常。用admin用户成功登陆后,再点击Hello BlazeDS按钮,则可以正确的取回Server端返回的字符串。
最后,准备部署到Google上,参考下面这篇文章,创建Google Appengine项目,并将BlazeDS项目复制到Google WebProject中。
http://jvalentino.blogspot.com/2009/06/flex-blazeds-google-app-engine-ja...
注意,用Flex编译客户端代码时,确保flexProperties文件中serverContextRoot="/",不能是调试时默认的比如WebBoxMaker。
注意这时,我们可以在本机正常运行BlazeDS应用程序了,但是一旦发布到Google Appengine上,运行时就会报错,因为Blazeds不能正确在Google Appengine上正确运行,需要修改一部分代码,这里参考了下面这篇文章,修改BlazeDS的程序,重新编译生成flex-messaging-core.jar.
http://martinzoldano.blogspot.com/2009/04/appengine-adobe-blazeds-fix.html
大家可以访问http://boxshotmaker.appspot.com/WebBoxshotMaker.html来运行我发布好的例子程序,例子程序的代码可以通过https://sharpplus.googlecode.com/svn/trunk/WebBoxshotMaker下载。