在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下载。