Autenticación HTTP básica con objetos HTTPService en Adobe Flex/AIR
http-authentication (8)
Además, para que otras personas no se pasen 10 minutos averiguando por qué el ejemplo correcto no funciona del todo, es necesario importar el paquete mx.utils.Base64Encoder, por ejemplo:
import mx.utils.Base64Encoder;
Al principio o en algún lugar dentro del área CDATA. Soy nuevo en flexión, así que esto no fue del todo obvio al principio.
Estoy intentando solicitar un recurso HTTP que requiera encabezados de autorización básicos desde una aplicación Adobe AIR. Intenté agregar manualmente los encabezados a la solicitud, así como también usar el método setRemoteCredentials () para establecerlos, sin éxito.
Aquí está el código:
<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" />
Sin embargo, sigue apareciendo un cuadro de diálogo de autenticación básica estándar que solicita al usuario su nombre de usuario y contraseña. Tengo la sensación de que no estoy haciendo esto de la manera correcta, pero toda la información que pude encontrar (documentos Flex, blogs, Google, etc.) no funcionó o fue demasiado vaga para ayudar.
¿Alguna magia negra, oh gurús Flex? Gracias.
EDITAR: Cambiar setRemoteCredentials () a setCredentials () produce el siguiente error de ActionScript:
[MessagingError message=''Authentication not supported on DirectHTTPChannel (no proxy).'']
EDITAR: problema resuelto, después de un poco de atención de Adobe. Vea las publicaciones a continuación para una explicación completa. Este código funcionará para los encabezados de Autenticación HTTP de longitud arbitraria.
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();
}
Ah. El dolor, el sufrimiento La pura miseria.
Mientras ha descubierto cómo agregar un encabezado antes de realizar su llamada, la desagradable realidad es que en algún lugar en el espacio de integración de Flash / navegador, sus encabezados se eliminarán nuevamente.
De mi blogpost el año pasado en verveguy.blogspot.com
Así que he desentrañado la Verdad. (Creo) Es más torturado de lo que uno podría imaginar
1 / Todas las solicitudes HTTP GET están desprovistas de encabezados. No está en la pila Flex, por lo que es probablemente el tiempo de ejecución de Flash Player subyacente
2 / Todas las solicitudes HTTP GET que tienen un tipo de contenido distinto de application/x-www-form-urlencoded
se convierten en solicitudes POST
3 / Todas las solicitudes HTTP POST que no tienen datos reales publicados se convierten en solicitudes GET. Ver 1 / y 2 /
4 / Todas las solicitudes HTTP PUT y HTTP DELETE se convierten en solicitudes POST. Esto parece ser una limitación del navegador que el Flash Player tiene. (?)
En términos prácticos, esto se reduce a que, si desea pasar encabezados en todas las solicitudes, siempre debe usar POST y debería encontrar otra forma de comunicar la semántica de la operación que "realmente quería". La comunidad de Rails se ha decidido a pasar ?_method=PUT/DELETE
como solución a los problemas del navegador 4 /
Dado que Flash agrega el maravilloso dolor de eliminación de encabezados en GET, también estoy usando ?_method=GET
como solución para eso. Sin embargo, dado que esto dispara en 3 /, estoy pasando un objeto ficticio como los datos codificados POST. Lo que significa que mi servicio necesita ignorar los datos publicados ficticios en una ?_method=GET
.
Crucial en este momento para saber aproximadamente 2 /. Eso desperdició un montón de mi tiempo.
Construí todo este manejo en una nueva clase RESTService con soporte de marcado MXML, por lo que es posible pretender que esto no existe en el lado del cliente.
Espero que esto ayude a alguien.
Así es como se hace.
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()};
Esto realmente me ha ayudado! ¡Gracias! Yo uso Flex Builder 3
Una nota: los encabezados de propiedad de WebService son de solo lectura. Así que traté de usar httpHeaders. ¡Funciona!
var encoder:Base64Encoder = new Base64Encoder();
encoder.insertNewLines = false;
encoder.encode("test:test");
sfWS.httpHeaders = {Authorization:"Basic " + encoder.toString()};
Finalmente recibió cierta atención de Adobe y obtuvo una respuesta sobre esto. El problema con los encabezados largos de Autenticación HTTP es que, de forma predeterminada, la clase Base64Encoder inyectará caracteres de nueva línea cada 72 caracteres. Obviamente, esto hace que un fragmento de la cadena codificada en base 64 se interprete como un nuevo atributo de encabezado, lo que causa el error.
Puede solucionar esto configurando (en el ejemplo anterior) encoder.insertNewLines = false; La configuración predeterminada es verdadera.
He corregido el código anterior para que funcione con cadenas de Autenticación arbitrariamente largas.
Intente utilizar setCredentials en lugar de setRemoteCredentials y, en su defecto, utilice Fiddler / Charles para averiguar qué encabezados se envían con la solicitud.
Los métodos setCredentials () y setRemoteCredentials () están destinados a ser utilizados con Flex / LiveCycle Data Services, por lo que probablemente no se apliquen en su caso.
Esto debería funcionar para usted. Pude reproducir este comportamiento en mi servidor, y esta solución parece haber hecho el truco; aún parece un poco extraño que esto no sea más amigable para el usuario de API, teniendo en cuenta cuán común es el caso de uso que uno podría pensar, pero no obstante, he probado y verificado que esto funciona, dado un certificado SSL válido:
private function authAndSend(service:HTTPService):void
{
var encoder:Base64Encoder = new Base64Encoder();
encoder.encode("someusername:somepassword");
service.headers = {Authorization:"Basic " + encoder.toString()};
service.send();
}
¡Espero eso ayude! Y gracias por publicar. Estoy seguro de que me habría topado con esto tarde o temprano. ;)
Tuve el mismo problema al consumir HTTP Basic Authenticated Webservice. Esta es mi solución; funciona bien:
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();
}
uso
authAndSend(WebService( aWebServiceWrapper.serviceControl));