Базовая аутентификация HTTP с объектами HTTPService в Adobe Flex/AIR
Я пытаюсь запросить ресурс HTTP, требующий основных заголовков авторизации из приложения Adobe AIR. Я попытался вручную добавить заголовки в запрос, а также использовать метод setRemoteCredentials(), чтобы установить их, безрезультатно.
Здесь код:
<mx:Script>
<![CDATA[
import mx.rpc.events.ResultEvent;
import mx.rpc.events.FaultEvent;
private function authAndSend(service:HTTPService):void
{
service.setRemoteCredentials('someusername', 'somepassword');
service.send();
}
private function resultHandler(event:ResultEvent):void
{
apiResult.text = event.result.toString();
}
private function resultFailed(event:FaultEvent):void
{
apiResult.text = event.fault.toString();
}
]]>
</mx:Script>
<mx:HTTPService id="apiService"
url="https://mywebservice.com/someFileThatRequiresBasicAuth.xml"
resultFormat="text"
result="resultHandler(event)"
fault="resultFailed(event)" />
<mx:Button id="apiButton"
label="Test API Command"
click="authAndSend(apiService)" />
<mx:TextArea id="apiResult" />
Тем не менее, появляется стандартное базовое диалоговое окно auth, в котором пользователь запрашивает имя пользователя и пароль. У меня такое чувство, что я не делаю этого правильно, но вся информация, которую я мог найти (документы Flex, блоги, Google и т.д.), Либо не работала, либо слишком расплывчата, чтобы помочь.
Любая черная магия, о губы Flex? Спасибо.
EDIT: Изменение setRemoteCredentials() на setCredentials() приводит к следующей ошибке ActionScript:
[MessagingError message='Authentication not supported on DirectHTTPChannel (no proxy).']
EDIT: Проблема решена, после некоторого внимания со стороны Adobe. См. Приведенные ниже сообщения для полного объяснения. Этот код будет работать для заголовков HTTP Authentication произвольной длины.
import mx.utils.Base64Encoder;
private function authAndSend(service:HTTPService):void
{
var encoder:Base64Encoder = new Base64Encoder();
encoder.insertNewLines = false; // see below for why you need to do this
encoder.encode("someusername:somepassword");
service.headers = {Authorization:"Basic " + encoder.toString()};
service.send();
}
Ответы
Ответ 1
Наконец, получил некоторое внимание от Adobe и получил ответ на это. Проблема с длинными заголовками HTTP-аутентификации заключается в том, что по умолчанию класс Base64Encoder будет вводить символы новой строки каждые 72 символа. Очевидно, что это приводит к тому, что фрагмент кодированной строки base-64 интерпретируется как новый атрибут заголовка, что вызывает ошибку.
Вы можете исправить это, установив (в приведенном выше примере) encoder.insertNewLines = false; Значение по умолчанию - true.
Я исправил вышеприведенный код для работы с произвольно длинными строками аутентификации.
Ответ 2
Ах. Боль, страдания. Явное несчастье.
Пока вы выяснили, как добавить заголовок перед тем, как сделать свой звонок, неприятная истина заключается в том, что где-то глубоко в пространстве интеграции Flash/браузера ваши заголовки снова удаляются.
Из моего blogpost в прошлом году на verveguy.blogspot.com
Итак, я разгадал Истину. (Я думаю)
Это более мучительно, чем можно было бы себе представить.
1/Все HTTP-запросы GET лишены заголовков. Это не в стеке Flex, поэтому он, вероятно, является базовым исполнением Flash Player
2/Все HTTP-запросы GET, имеющие тип контента, отличный от application/x-www-form-urlencoded
, преобразуются в запросы POST
3/Все запросы HTTP POST, которые не имеют фактических данных, превращаются в запросы GET. См. 1/и 2/
4/Все запросы HTTP PUT и HTTP DELETE превращаются в запросы POST. Похоже, это ограничение браузера, за которое застрял Flash-плеер. (?)
На практике это сводится к тому, что если вы хотите передавать заголовки во всех запросах, вы всегда должны использовать POST, и вы должны найти другой способ передачи семантики операции, которую вы действительно хотели. Сообщество Rails решило передать ?_method=PUT/DELETE
как работу для проблем браузера, лежащих в основе 4/
Так как Flash добавляет прекрасную боль в заголовке GET, я также использую ?_method=GET
как обходной путь для этого. Однако, поскольку это срабатывает на 3/,
Я передаю фиктивный объект в качестве закодированных данных POST. Это означает, что мой сервис должен игнорировать фиктивные данные в запросе ?_method=GET
.
В этот момент важно знать о 2/. Это потратило кучу моего времени.
Я построил всю эту обработку в новом классе RESTService с поддержкой разметки MXML, чтобы можно было сделать вид, что этого не существует на стороне клиента.
Надеюсь, это поможет кому-то.
Ответ 3
Методы setCredentials() и setRemoteCredentials() предназначены для использования с службами данных Flex/LiveCycle Data Services, поэтому они, вероятно, не применяются в вашем случае.
Это должно сработать для вас. Я смог воспроизвести это поведение на своем сервере, и это исправление, похоже, сделало трюк; это все еще кажется немного странным, это не является более удобным для API-интерфейсом, учитывая, насколько распространенным является случай использования, который вы так думаете, но, тем не менее, я тестировал и проверял, что это работает, учитывая действительный сертификат SSL:
private function authAndSend(service:HTTPService):void
{
var encoder:Base64Encoder = new Base64Encoder();
encoder.encode("someusername:somepassword");
service.headers = {Authorization:"Basic " + encoder.toString()};
service.send();
}
Надеюсь, это поможет! И спасибо за сообщение - я уверен, что рано или поздно я столкнулся с этим.;)
Ответ 4
Это действительно помогло мне! Благодарю!
Я использую Flex Builder 3
Одно примечание: заголовки свойств WebService доступны только для чтения.
Поэтому я попытался использовать httpHeaders. Он работает!
var encoder:Base64Encoder = new Base64Encoder();
encoder.insertNewLines = false;
encoder.encode("test:test");
sfWS.httpHeaders = {Authorization:"Basic " + encoder.toString()};
Ответ 5
У меня была та же проблема при использовании HTTP Basic Authenticated Webservice. Это мое решение; он отлично работает:
private function authAndSend(service:WebService):void
{
var encoder:Base64Encoder = new Base64Encoder();
encoder.insertNewLines = false;
encoder.encode("user:password");
service.httpHeaders = { Authorization:"Basic " + encoder.ToString() };
service.initialize();
}
использование
authAndSend(WebService( aWebServiceWrapper.serviceControl));
Ответ 6
Попробуйте использовать setCredentials, а не setRemoteCredentials, и не получив этого, используя Fiddler/Charles, чтобы узнать, какие заголовки отправляются с запросом.
Ответ 7
Кроме того, просто потому, что другие люди не тратят 10 минут на то, почему правильный пример не работает asis, вам нужно импортировать mx.utils.Base64Encoder, например:
import mx.utils.Base64Encoder;
В начале или где-то в области CDATA. Я новичок в flex, поэтому сначала это было не совсем очевидно.
Ответ 8
Вот как это делается.
import mx.utils.Base64Encoder;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.http.HTTPService;
var _oHttp:HTTPService = new HTTPService;
var sUsername:String = "theusername"
var sPassword:String = "thepassword";
var oEncoder:Base64Encoder = new Base64Encoder();
oEncoder.insertNewLines = false;
oEncoder.encode(sUsername + ":" + sPassword);
_oHttp.method = "POST";
_oHttp.headers = {Authorization:"Basic " + oEncoder.toString()};