定制基于Tomcat的Flex认证

首先,我们先来实现基本认证(Basic)

1.编辑Tomcat的conf目录下的tomcat-users.xml添加用户名及角色定义

<?xml version='1.0' encoding='utf-8'?>
<tomcat-users>
  <role rolename="managers"/>
  <user username="abc" password="abc" roles="managers"/>
</tomcat-users>

2.编辑BlazeDS的Samples应用的Services-config.xml添加安全设置

    <security>
        <login-command class="flex.messaging.security.TomcatLoginCommand" server="Tomcat">
            <per-client-authentication>false</per-client-authentication>
        </login-command>
   
        <security-constraint id="trusted">
            <auth-method>Custom</auth-method>
            <roles>
                <role>managers</role>
            </roles>
        </security-constraint>
    </security>   

3.编辑Samples应用的remoting-config.xml对指定的Service添加安全设置

    <destination id="consultantService">
        <properties>
            <source>com.adobe.demo.ConsultantService
            </source>
        </properties>
        <security>
            <security-constraint ref="trusted"/>
        </security>
    </destination>

4.然后修改Samples应用的Web.xml,添加安全设置定义

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Protected Sample</web-resource-name>

            <url-pattern>/messagebroker/amf/*</url-pattern>
            <http-method>GET</http-method>
            <http-method>POST</http-method>
        </web-resource-collection>

        <auth-constraint>
            <role-name>managers</role-name>
        </auth-constraint>
    </security-constraint>
   

    <login-config>
        <auth-method>BASIC</auth-method>
    </login-config>

   
    <security-role>
        <role-name>managers</role-name>
    </security-role>

5.创建一个简单的Flex应用,实现自定义的登录

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
    xmlns:mx="http://www.adobe.com/2006/mxml"
    xmlns:view="com.adobe.demo.view.*"
    backgroundColor="#FFFFFF"
     initialize="creationCompleteHandler();"
    >
    <mx:Script>
        <![CDATA[
            import mx.controls.Alert;
            import mx.messaging.config.ServerConfig;
            import mx.rpc.AsyncToken;
            import mx.rpc.AsyncResponder;
            import mx.rpc.events.FaultEvent;
            import mx.rpc.events.ResultEvent;
            import mx.messaging.ChannelSet;

            // Define a ChannelSet object.
            public var cs:ChannelSet;
           
            // Define an AsyncToken object.
            public var token:AsyncToken;

            // Initialize ChannelSet object based on the
            // destination of the RemoteObject component.
            private function creationCompleteHandler():void {
                if (cs == null)
                    cs = ServerConfig.getChannelSet(loaderService.destination);
                //login
                Alert.show("Init");    
            }

            // Login and handle authentication success or failure.
            private function ROLogin():void {
                // Make sure that the user is not already logged in.
                if (cs.authenticated == false) {
                    token = cs.login("abc", "abc");
                    // Add result and fault handlers.
                    token.addResponder(new AsyncResponder(LoginResultEvent, LoginFaultEvent));
                }
            }

            // Handle successful login.
            private function LoginResultEvent(event:ResultEvent, token:Object=null):void  {
                switch(event.result) {
                    case "success":
                        authenticatedCB.selected = true;
                        Alert.show("login successfully");
                    break;
                    default:
                }
            }
           
            // Handle login failure.
            private function LoginFaultEvent(event:FaultEvent, token:Object=null):void {
                switch(event.fault.faultCode) {
                    case "Client.Authentication":
                        default:
                            authenticatedCB.selected = false;
                            Alert.show("Login failure: " + event.fault.faultString);
                }
            }

            // Logout and handle success or failure.
            private function ROLogout():void {
                // Add result and fault handlers.
                token = cs.logout();
                token.addResponder(new AsyncResponder(LogoutResultEvent,LogoutFaultEvent));
            }

            // Handle successful logout.
            private function LogoutResultEvent(event:ResultEvent, token:Object=null):void {
                switch (event.result) {
                    case "success":
                        //authenticatedCB.selected = false;
                        Alert.show("logout successfully");
                        break;
                    default:
                }
            }

            // Handle logout failure.
            private function LogoutFaultEvent(event:FaultEvent, token:Object=null):void {
                Alert.show("Logout failure: " + event.fault.faultString);
            }

            // Handle message recevied by RemoteObject component.
            private function resultHandler(event:ResultEvent):void {
                //ta.text += "Server responded: "+ event.result + "\n";
                Alert.show("Ok loading data");
            }

            // Handle fault from RemoteObject component.
            private function faultHandler(event:FaultEvent):void {
                //ta.text += "Received fault: " + event.fault + "\n";
                Alert.show("error loading data");
            }
        ]]>
    </mx:Script>

    <mx:HBox>
        <mx:Button label="Login"
            click="ROLogin();"/>
        <mx:Button label="Load Data" 
            click="loaderService.loadConsultants();"/>
        <mx:Button label="Logout"
            click="ROLogout();"/>
        <mx:CheckBox id="authenticatedCB"
            label="Authenticated?"
            enabled="false"/>
    </mx:HBox>
   
    <mx:RemoteObject id="loaderService" destination="consultantService" result="resultHandler(event)"    fault="faultHandler(event)" showBusyCursor="true" />

</mx:Application>
 

 接下来我们实现基于JDBC的用户登录认证

1.创建用户管理表

CREATE TABLE users (
  username         varchar(15) NOT NULL PRIMARY KEY,
  password         varchar(15) NOT NULL
);
 
CREATE TABLE user_roles (
  username          varchar(15) NOT NULL,
  role              varchar(15) NOT NULL,
  PRIMARY KEY (username, role)

);

2.复制Mysql 的JDBC Driver到Tomcat lib目录下,编辑Server.xml文件,将Realm的类从UserDatabase

改成JDBCRealm

      <!-- Realm className="org.apache.catalina.realm.UserDatabaseRealm"
             resourceName="UserDatabase"/ -->
      <Realm  className="org.apache.catalina.realm.JDBCRealm" debug="99"
              driverName="com.mysql.jdbc.Driver"
              connectionURL="jdbc:mysql://localhost/consultant_db?user=root&amp;password=root"
              userTable="users" userNameCol="username" userCredCol="password"
              userRoleTable="user_roles" roleNameCol="role"/>

3.在Samples应用目录下创建Context.xml

<!--
Enable the TomcatValve for custom login support from this webapp.
-->
<Context>
    <Realm className="org.apache.catalina.realm.JDBCRealm" />
    <Valve className="flex.messaging.security.TomcatValve"/>
</Context>

重新运行上面的Flex客户端,你会发现我们已经可以使用Datbase中的用户名和密码进行验证了。