Модуль авторизации для Flex-приложений (part 2)
Продолжение по теме: “Модуль авторизации для Flex-приложений”
начало тут
Итак строим Flex-client side
Проект состоит из следующих файлов.
1. index.mxml – главное приложение в котором нам необходима авторизация
2. com/control/maincontrol.as – вся логика главного приложения по обработке событий авторизации
3. com/events/LoginEvent.as – Custom event при помощи которого передаем данные в главное приложение
4. com/view/LoginWindow.mxml – модуль авторизации, построенный на базе TitleWindow
5. com/vo/GALLuserVO.as – value-object класс содержащий все данные пользователя
Логика:
- По нажатию кнопки “cbLogin” создается окно для авторизации
- в LoginWindow по нажатию кнопки “cbSubmit” передаются данные (login/password) в файл login.php
- login.php генерирует различные XML (смотри part1)
- LoginWindow анализирует входящие XML и генерирует alert или объект с данными
- объект с данными передается через CustomEvent главному приложению
Несколько замечаний:
- Естественно в реальном приложении данные об ошибках не выводятся пользователю, а пишутся в лог-файл.

Структура проекта
главный файл
index.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute">
<mx:Style>
Application
{
paddingLeft: 10px;
paddingRight: 10px;
paddingTop: 10px;
paddingBottom: 10px;
backgroundGradientColors: #2F3D45, #5B7685;
}
Alert
{
backgroundColor:#eeeeee;
color: #323232;
borderColor: #cc0000;
fontWeight:bold;
borderAlpha: 0.7;
headerHeight:20;
themeColor: #848484;
titleStyleName:alertTitle;
}
.alertTitle
{
color:#ffffff;
fontWeight:bold;
}
</mx:Style>
<!-- базовая логика -->
<mx:Script source="com/control/maincontrol.as"/>
<mx:ApplicationControlBar id="appContolBar" dock="true" paddingTop="2" paddingBottom="2" alpha="1.0">
<mx:Spacer width="100%" />
<mx:Button id="cbLogin" label="Login"
click="showLoginWindow()"
icon="@Embed(source='assets/icons/user.png')"
/>
</mx:ApplicationControlBar>
</mx:Application>
и файл базовой логики maincontrol.as
/******************************************************************************
* импорт components
******************************************************************************/
// import своих компонент
import com.events.LoginEvent;
import com.view.LoginWindow;
import com.vo.GALLuserVO;
// Импорт Flex компонент
import mx.controls.Alert;
import mx.managers.PopUpManager;
/******************************************************************************
* объявление переменных
******************************************************************************/
// переменная содержащая данные пользователя
private var userData:GALLuserVO;
// создание переменных для окон
private var loginWindow:LoginWindow;
/******************************************************************************
* блок обработки кнопок
******************************************************************************/
// перехватчик нажатия кнопки Login
private function showLoginWindow():void{
// добавляем окно авторизации в главное приложение
var loginForm:LoginWindow = LoginWindow(PopUpManager.createPopUp(this, LoginWindow, false));
loginForm.setStyle("borderAlpha", 0.8);
// добавляем прослушку окна Login
loginForm.addEventListener("user", loginFormHandler);
}
// перехватчик события по авторизации
private function loginFormHandler(event:LoginEvent):void{
// получаем данные из евента
userData = event.userVO;
//выводим на экран данные о пользователе
var UserMessage:String = event.userVO.usersUsername;
UserMessage += "\n\n" + event.userVO.usersFirstname;
UserMessage += "\n\n" + event.userVO.usersLastname;
UserMessage += "\n\n" + event.userVO.usersDepartment;
UserMessage += "\n\n" + event.userVO.usersAppointment;
UserMessage += "\n\n" + event.userVO.usersEmail;
UserMessage += "\n\n" + event.userVO.usersPermission;
Alert.show(UserMessage, "Данные о пользователе");
// в принципе здесь размещаем переход на действие которое мы планируем...
// do it something with userdata
// я в зависимости от содержания usersPermission открывал некоторые кнопки
}
/******************************************************************************
* конец
******************************************************************************/
В итоге получим примерно такую картинку:

Создаем новый MXML component
LoginWindow.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml"
horizontalCenter="0" verticalCenter="0"
layout="absolute"
width="200" height="200"
title="Авторизация"
status="Close"
creationComplete="init();"
showCloseButton="true"
close="closeWin()"
>
<!-- обязательный тег с метаданными где мы присваиваем имя нашему Custom Event -->
<mx:Metadata>
[Event(name="user", type="com.events.LoginEvent")]
</mx:Metadata>
<mx:Script>
<![CDATA[
import com.events.LoginEvent;
import com.vo.GALLuserVO;
import mx.controls.Alert;
import mx.managers.PopUpManager;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.http.HTTPService;
private var tempUserName:String;
private var myData:Object;
private var UserData:GALLuserVO = new GALLuserVO();
private var gateway:HTTPService = new HTTPService();
private function init():void{
PopUpManager.centerPopUp(this);
username.setFocus();
}
private function closeWin():void{
// сброс полей
username.text = "";
password.text = "";
// убираем с экрана
PopUpManager.removePopUp(this);
}
private function loginSubmitHanler():void {
// объект содержащий поля с логином и паролем для отсылки
var UserLoginObj:Object;
UserLoginObj = {"username":username.text, "password":password.text};
// отправка на проверку имени и пароля
sendUser(UserLoginObj);
}
private function sendUser(setUser:Object):void
{
// сохраняем имя
tempUserName = setUser.username;
// заносим в запрос данные и отправляем на сервер
gateway.url = "assets/php/login.php";
gateway.method = "POST";
gateway.useProxy = false;
gateway.showBusyCursor = true;
gateway.addEventListener(ResultEvent.RESULT, checkUser);
gateway.addEventListener(FaultEvent.FAULT, faultHandler);
gateway.request = setUser;
gateway.send();
}
private function checkUser(event:ResultEvent):void
{
// загружаем данные из XML
myData = event.result.data;
// проверка ошибок соединения
if (myData.error == "yes")
{
// передаем в алерт описание ошибки
mySQLAlert(myData.error_num, myData.error_desc);
}
else
{
// успешное соединение - пользователь есть в базе
if(myData.loginsuccess == "yes")
{
// наполнение объекта данными
UserData.usersUsername = tempUserName;
UserData.usersFirstname = myData.Ufirstname
UserData.usersLastname = myData.Ulastname;
UserData.usersEmail = myData.Uemail;
UserData.usersDepartment = myData.Udepartment;
UserData.usersAppointment = myData.Uappointment;
UserData.usersPermission = myData.Upermission;
// сброс полей
username.text = "";
password.text = "";
// отправка данных через евент в главное приложение
var e:LoginEvent = new LoginEvent("user", UserData);
dispatchEvent(e);
// закрываем окно
closeWin();
}
else
// успешное соединение - но пользователя нет в базе
{
// сброс полей
username.text = "";
password.text = "";
Alert.show("Invalid username or password", "Alert!");
}
}
}
/******************************************************************************
* отслеживание ошибок mySQl и при соединении
******************************************************************************/
private function mySQLAlert (num:String, message:String):void
{
Alert.show(message, "mySQL Error! " + "Error #" + num);
}
private function faultHandler(event:FaultEvent):void
{
var errorMessage:String = "Connection error: " + event.fault.faultString;
if (event.fault.faultDetail)
{
errorMessage += "\n\nAdditional detail: " + event.fault.faultDetail;
}
Alert.show(errorMessage);
}
]]>
</mx:Script>
<mx:Label x="10" y="10" text="Login:" width="160"/>
<mx:TextInput x="10" y="36" id="username" width="160"/>
<mx:Label x="10" y="66" text="Password:" width="160"/>
<mx:TextInput id="password"
x="10" y="92"
displayAsPassword="true"
enter="loginSubmitHanler()"
width="160"/>
<mx:Button id="cbSubmit"
label="OK"
click="loginSubmitHanler()"
x="10" y="122"
width="75"/>
<mx:Button id="cbCancel"
label="Cancel"
click="closeWin()"
x="95" y="122"
width="75"
/>
</mx:TitleWindow>
Внешний вид:

Сопутствующие файлы: LoginEvent.as – Custom Event
package com.events
{
import com.vo.GALLuserVO;
import flash.events.Event;
public class LoginEvent extends Event
{
public var userVO:GALLuserVO;
public function LoginEvent(type:String, userVO:GALLuserVO)
{
super(type);
this.userVO = userVO;
}
}
}
и GALLuserVO.as – value-object class
package com.vo
{
public class GALLuserVO
{
public var usersUsername:String;
public var usersFirstname:String;
public var usersLastname:String;
public var usersEmail:String;
public var usersDepartment:String;
public var usersAppointment:String;
public var usersPermission:String;
}
}
При успешном запросе мы получаем следующие данные в дебаге:

или для отладки через Alert:

Для различных ситуаций с ошибками выводятся следующие алярмы.
1. Не прошла авторизация

2. Ошибка при коннекте с базой данных

3. Ошибка в синтаксисе SQL

Вроде как все. Готов выслушать предложения по улучшению данного модуля
Не подскажешь а как зделать 2 и более окон и чтобы между ними можно было переключатся и двигать их?
Что есть окна? Браузера, Флеш-плеера, 2 панели внутри флеша? можешь уточнить что имеешь ввиду?
что нибудь похожее на titlewindows. Хотя если с помощью flex можно из одного окна открывать еще окна флеш-плеера это тоже очень интересно.
Естественно, можно вызвать хоть 3 окна типа TitleWindow.
Обрати внимание:
в файле логики, где обрабатываем нажатие кнопки:
// добавляем окно авторизации в главное приложение
var loginForm:LoginWindow = LoginWindow(PopUpManager.createPopUp(this, LoginWindow, false));
Последний параметр (true / false) управляет модальностью окна, то есть будет ли это окно блокировать доступ к другим окнам.
Никто не мешает сделать еще одно окно, условно:
var loginForm2:LoginWindow = LoginWindow(PopUpManager.createPopUp(this, LoginWindow, false));
Изменение размеров… я как то не особо интересовался на эту тему. Погугли, ребята пишут свои расширения для этого, и если меня не подводит память в 4м Flexe – компонент Spark TitleWindow может это делать…
Лучше уж сразу AMFPHP – а то переделывать будет муторно.