Flex 3 - как поддерживать URLRequest HTTP-аутентификации?
-
21-08-2019 - |
Вопрос
У меня есть скрипт загрузки гибких файлов, который использует 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, поскольку в настоящее время у меня его нет, и я не уверен, где его разместить.
Решение
Синтаксис 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 (с отладочными и релизными SWFS), поэтому он должен работать у вас, но я хотел обновить свой исходный пост, включив всю эту дополнительную информацию на случай, если у вас возникнут какие-либо проблемы, поскольку шансы кажутся (к сожалению) вероятными, что так и будет.
Надеюсь, это поможет!Удачи.Я буду следить за комментариями.
Другие советы
Методы 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();
Казалось бы, аналогичная проблема была решена здесь.Я настоятельно призываю вас также проверить Сообщение флекскодеров ссылка приведена в первом посте.
В чем проблема заключалось в том, что FireFox использует отдельный экземпляр окна браузера для отправки запроса на загрузку файла. Решение заключается в том, чтобы вручную прикрепить идентификатор сеанса к URL-адресу запроса.Идентификатор сеанса присоединяется не как обычная переменная GET, а с точкой с запятой (причина такого синтаксиса мне неизвестна).
Flash очень ограничен с точки зрения того, какие заголовки вы можете передавать с http-запросом (и это меняется в разных браузерах и операционных системах).Если вы заставите это работать в одном браузере / операционной системе, обязательно протестируйте это на других.
Лучшее, что можно сделать, это не связываться с HTTP-заголовками.
У нас такая же проблема (загрузка в веб-альбомы Picasa с flash) и публикация через прокси на нашем сервере.Мы передаем дополнительные заголовки в качестве параметров post, и наш прокси-сервер делает все правильно.
"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.Напишите мне, если хотите, чтобы они написали код.Чтобы решить вышеуказанную проблему на страницах, где файлы cookie для аутентификации должны быть отправлены по 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 проверьте наличие параметров
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;
Наконец, вставьте файлы cookie в 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 закрыла проблему как неразрешимую, так что это было мое последнее средство.