Flex 3 - как поддерживать HTTP-аутентификацию URLRequest?
У меня есть скрипт загрузки файлов Flex, который использует URLRequest для загрузки файлов на сервер. Я хочу добавить поддержку http-аутентификации (каталоги, защищенные паролем на сервере), но я не знаю, как это реализовать - я предполагаю, что мне нужно как-то расширить класс, но я немного растерялся.
Я попытался изменить следующее (заменив HTTPService на URLRequest), но это не сработало.
private function authAndSend(service:HTTPService):void{
var encoder:Base64Encoder = new Base64Encoder();
encoder.encode("someusername:somepassword");
service.headers = {Authorization:"Basic " + encoder.toString()};
service.send();
}
Я должен отметить, что я не разбираюсь в ActionScript / Flex, хотя мне удалось несколько изменить сценарий загрузки.
[Изменить] - вот обновление моего прогресса, основанное на ответе ниже, хотя я все еще не могу заставить это работать:
Спасибо за помощь. Я пытался реализовать ваш код, но мне не повезло.
Общее поведение, которое я испытываю при работе с местоположениями, прошедшими проверку подлинности HTTP, заключается в том, что с IE7 все хорошо, но в Firefox, когда я пытаюсь загрузить файл на сервер, он отображает запрос проверки подлинности HTTP - который, даже если предоставить правильные данные, просто останавливается Процесс загрузки.
Я считаю, что причина того, что IE7 в порядке, заключается в том, что информация о сеансе / аутентификации передается браузеру и компоненту Flash - однако в Firefox это не так, и я испытываю описанное выше поведение.
Вот моя обновленная функция загрузки, включающая ваши изменения:
private function pergress():void
{
if (fileCollection.length == 0)
{
var urlString:String = "upload_process.php?folder="+folderId+"&type="+uploadType+"&feid="+formElementId+"&filetotal="+fileTotal;
if (ExternalInterface.available)
{
ExternalInterface.call("uploadComplete", urlString);
}
}
if (fileCollection.length > 0)
{
fileTotal++;
var urlRequest:URLRequest = new URLRequest("upload_file.php?folder="+folderId+"&type="+uploadType+"&feid="+formElementId+"&obfuscate="+obfuscateHash+"&sessidpass="+sessionPass);
urlRequest.method = URLRequestMethod.POST;
urlRequest.data = new URLVariables("name=Bryn+Jones");
var encoder:Base64Encoder = new Base64Encoder();
encoder.encode("testuser:testpass");
var credsHeader:URLRequestHeader = new URLRequestHeader("Authorization", "Basic " + encoder.toString());
urlRequest.requestHeaders.push(credsHeader);
file = FileReference(fileCollection.getItemAt(0));
file.addEventListener(Event.COMPLETE, completeHandler);
file.addEventListener(HTTPStatusEvent.HTTP_STATUS, onHTTPStatus);
file.addEventListener(ProgressEvent.PROGRESS, onUploadProgress);
file.upload(urlRequest);
}
}
Как указано выше, я, кажется, испытываю те же результаты с поправками к моей функции или без нее.
Могу ли я также спросить, где должен находиться файл crossdomain.xml, поскольку у меня его нет и я не уверен, где его разместить.
9 ответов
Синтаксис немного отличается для URLRequest, но идея та же:
private function doWork():void
{
var req:URLRequest = new URLRequest("http://yoursite.com/yourservice.ext");
req.method = URLRequestMethod.POST;
req.data = new URLVariables("name=John+Doe");
var encoder:Base64Encoder = new Base64Encoder();
encoder.encode("yourusername:yourpassword");
var credsHeader:URLRequestHeader = new URLRequestHeader("Authorization", "Basic " + encoder.toString());
req.requestHeaders.push(credsHeader);
var loader:URLLoader = new URLLoader();
loader.load(req);
}
Несколько вещей, чтобы иметь в виду:
Лучше всего я могу сказать, по какой-то причине, это работает только тогда, когда метод запроса POST; Заголовки не устанавливаются с помощью запросов GET.
Интересно, что также происходит сбой, если по крайней мере одна пара имя-значение URLVariables не будет упакована с запросом, как указано выше. Вот почему многие примеры, которые вы видите там (включая мой), прикрепляют "name=John+Doe" - это просто заполнитель для некоторых данных, которые, по-видимому, требуется URLRequest при установке любых пользовательских заголовков HTTP. Без этого даже должным образом аутентифицированный запрос POST также потерпит неудачу.
Очевидно, что Flash Player версии 9.0.115.0 полностью блокирует все заголовки авторизации (более подробную информацию об этом здесь), так что вы, вероятно, также захотите помнить об этом.
Вам почти наверняка придется изменить свой файл crossdomain.xml, чтобы он соответствовал заголовкам, которые вы собираетесь отправлять. В моем случае я использую это, который является довольно широко открытым файлом политики, поскольку он принимает из любого домена, поэтому в вашем случае вы можете захотеть ограничить вещи немного больше, в зависимости от того, насколько вы заботитесь о безопасности,
crossdomain.xml:
<?xml version="1.0"?>
<cross-domain-policy>
<allow-access-from domain="*" />
<allow-http-request-headers-from domain="*" headers="Authorization" />
</cross-domain-policy>
... и это похоже на работу; более подробную информацию об этом можно получить в Adobe здесь).
Приведенный выше код был протестирован с Flash Player 10 (с отладкой и выпуском SWF), поэтому он должен работать для вас, но я хотел обновить свой оригинальный пост, чтобы включить всю эту дополнительную информацию на случай, если у вас возникнут какие-либо проблемы, так как шансы кажутся (грустно) вероятно, что вы будете.
Надеюсь, поможет! Удачи. Я буду следить за комментариями.
Методы FileReference.upload() и FileReference.download() не поддерживают параметр URLRequest.requestHeaders.
http://livedocs.adobe.com/flex/2/langref/flash/net/URLRequest.html
Если вы хотите загрузить файл, вам просто нужно отправить правильные заголовки и содержимое файла, используя URLRequest через класс UploadPostHelper. Это работает на 100%, я использую этот класс для загрузки сгенерированных изображений и файлов CSV, но вы можете загрузить любой вид файла.
Этот класс просто подготавливает запрос с заголовками и содержимым, как если бы вы загружали файл из HTML-формы.
http://code.google.com/p/as3asclublib/source/browse/trunk/net/UploadPostHelper.as?r=118
_urlRequest = new URLRequest(url);
_urlRequest.data = "LoG";
_urlRequest.method = URLRequestMethod.POST;
_urlRequest.requestHeaders.push(new URLRequestHeader("X-HTTP-Code-Override", "true"));
_urlRequest.requestHeaders.push(new URLRequestHeader("pragma", "no-cache"));
initCredentials();
_loader.dataFormat = URLLoaderDataFormat.BINARY;
//this creates a security problem, putting the content type in the headers bypasses this problem
//_urlRequest.contentType = 'multipart/form-data; boundary=' + UploadPostHelper.getBoundary();
_urlRequest.requestHeaders.push( new URLRequestHeader( 'Cache-Control', 'no-cache' ) );
_urlRequest.requestHeaders.push(new URLRequestHeader('Content-Type', 'multipart/form-data; boundary=' + UploadPostHelper.getBoundary()));
_urlRequest.data = UploadPostHelper.getPostData("file.csv", param[1]);
_loader.load(_urlRequest);
Я не уверен в этом, но вы пытались добавить имя пользователя: пароль @ в начале вашего URL?
var service : HTTPService = new HTTPService ();
var encoder:Base64Encoder = new Base64Encoder();
encoder.insertNewLines = false;
encoder.encode("user:password");
service.headers = {Authorization:"Basic " + encoder.toString()};
service.method = HTTPRequestMessage.POST_METHOD;
service.request = new URLVariables("name=John+Doe");
service.addEventListener(FaultEvent.FAULT,error_handler );
service.addEventListener(ResultEvent.RESULT,result_handler);
service.url = 'http://blah.blah.xml?'+UIDUtil.createUID();
service.send();
" http://username:password@yoursite.com/yourservice.ext"
Это не работает в IE ( http://www.theregister.co.uk/2004/01/30/ms_drop_authentication_technique/) и, похоже, не работает в Chrome.
вероятно, не используется во Flash
Вот обходной путь при использовании ASP.Net, частично основанный на работе здесь.
Я создал компонент, который динамически записывает объекты Flex на страницу, чтобы их можно было использовать в UpdatePanels. Напишите мне, если вы хотите, чтобы они кодировали. Чтобы решить вышеупомянутую проблему на страницах, где URLRequest нужно будет отправлять куки для аутентификации, я добавляю значения в качестве flashVars.
Этот код работает только в моем объекте, но вы поняли идею
Dictionary<string, string> flashVars = new Dictionary<string, string>();
flashVars.Add("auth", Request.Cookies["LOOKINGGLASSFORMSAUTH"].Value);
flashVars.Add("sess", Request.Cookies["ASP.NET_SessionId"].Value);
myFlexObject.SetFlashVars(flashVars);
Затем в Flex Object проверьте параметры
if (Application.application.parameters.sess != null)
sendVars.sess= Application.application.parameters.sess;
if (Application.application.parameters.auth != null)
sendVars.au= Application.application.parameters.auth;
request.data = sendVars;
request.url = url;
request.method = URLRequestMethod.POST;
Наконец, добавьте куки в global.asax BeginRequest
if (Request.RequestType=="POST" && Request.Path.EndsWith("upload.aspx"))
{
try
{
string session_param_name = "sess";
string session_cookie_name = "ASP.NET_SESSIONID";
string session_value = Request.Form[session_param_name]; // ?? Request.QueryString[session_param_name];
if (session_value != null) { UpdateCookie(session_cookie_name, session_value); }
}
catch (Exception) { }
try
{
string auth_param_name = "au";
string auth_cookie_name = FormsAuthentication.FormsCookieName;
string auth_value = Request.Form[auth_param_name];// ?? Request.QueryString[auth_param_name];
if (auth_value != null) { UpdateCookie(auth_cookie_name, auth_value); }
}
catch (Exception) { }
}
Надеюсь, это поможет кому-то избежать 6 часов, которые я потратил на решение этой проблемы. Adobe закрыла вопрос как неразрешимый, так что это было мое последнее средство.
Казалось бы, подобная проблема была решена здесь. Я призываю вас также проверить сообщение Flexcoders, на которое есть ссылка в первом сообщении.
Проблема заключалась в том, что FireFox использует отдельный экземпляр окна браузера для отправки запроса на загрузку файла. Решение состоит в том, чтобы вручную прикрепить идентификатор сеанса к URL-адресу запроса. Идентификатор сеанса прикрепляется не как обычная переменная GET, а с точкой с запятой (причина этого синтаксиса мне неизвестна).
Flash очень ограничен с точки зрения того, какой тип заголовков вы можете передать с помощью http-запроса (и он меняется между браузерами и операционными системами). Если вы работаете с одним браузером / ОС, убедитесь, что вы тестировали его на других.
Лучше всего не связываться с заголовками HTTP.
У нас та же проблема (загрузка в Веб-альбомы Picasa из флэш-памяти) и публикация через прокси на нашем сервере. Мы передаем дополнительные заголовки в качестве параметров публикации, и наш прокси-сервер делает правильные вещи.