web-dev-qa-db-fra.com

Authentification HTTP de base avec des objets HTTPService dans Adobe Flex/AIR

J'essaie de demander une ressource HTTP nécessitant des en-têtes d'autorisation de base à partir d'une application Adobe AIR. J'ai essayé d'ajouter manuellement les en-têtes à la demande, ainsi que d'utiliser la méthode setRemoteCredentials () pour les définir, mais en vain.

Voici le code:

<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" />

Cependant, une boîte de dialogue d'authentification de base standard apparaît toujours, invitant l'utilisateur à entrer son nom d'utilisateur et son mot de passe. J'ai l'impression que je ne le fais pas correctement, mais toutes les informations que j'ai pu trouver (documents Flex, blogs, Google, etc.) n'ont pas fonctionné ou étaient trop vagues pour vous aider.

Une magie noire, oh gourous Flex? Merci.


EDIT: La modification de setRemoteCredentials () en setCredentials () génère l'erreur ActionScript suivante:

[MessagingError message='Authentication not supported on DirectHTTPChannel (no proxy).']

EDIT: Problème résolu, après une attention de la part d'Adobe. Voir les messages ci-dessous pour une explication complète. Ce code fonctionnera pour les en-têtes d'authentification HTTP de longueur arbitraire.

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();
}
31
Bob Somers

Enfin, Adobe a fait l’objet d’une attention particulière et a obtenu une réponse à ce sujet. Le problème des en-têtes d'authentification HTTP longs est que, par défaut, la classe Base64Encoder injecte des caractères de nouvelle ligne tous les 72 caractères. Évidemment, cela provoque l'interprétation d'une partie de la chaîne codée en base 64 comme un nouvel attribut d'en-tête, ce qui provoque l'erreur.

Vous pouvez résoudre ce problème en définissant (dans l'exemple ci-dessus) encoder.insertNewLines = false; Le paramètre par défaut est true.

J'ai corrigé le code ci-dessus pour qu'il fonctionne avec des chaînes d'authentification arbitrairement longues.

13
Bob Somers

Ah La douleur, la souffrance La pure misère. 

Bien que vous ayez compris comment ajouter un en-tête avant de passer votre appel, la vérité est que, quelque part au fond de l’espace d’intégration Flash/navigateur, vos en-têtes sont à nouveau supprimés.

De mon blogpost l'année dernière à verveguy.blogspot.com

J'ai donc dévoilé la vérité. (Je pense) C'est plus torturé qu'on pourrait l'imaginer

1/Toutes les requêtes HTTP GET sont dépourvues d'en-têtes. Ce n'est pas dans la pile Flex, c'est donc probablement le moteur d'exécution sous-jacent de Flash Player

2/Toutes les requêtes HTTP GET dont le type de contenu est autre que application/x-www-form-urlencoded sont transformées en requêtes POST

3/Toutes les demandes HTTP POST ne contenant aucune donnée validée sont transformées en demandes GET. Voir 1/et 2 /

4/Toutes les requêtes HTTP PUT et HTTP DELETE sont transformées en requêtes POST. Cela semble être une limitation du navigateur qui bloque le lecteur Flash. (?)

Cela revient concrètement à dire que si vous voulez passer des en-têtes dans toutes les demandes, vous devez toujours utiliser POST et trouver un autre moyen de communiquer la sémantique de l'opération que vous "souhaitiez vraiment". La communauté Rails a décidé de passer ?_method=PUT/DELETE comme solution de contournement aux problèmes de navigateur sous-jacents 4 /

Depuis que Flash ajoute l’entête merveilleuse qui soulage la douleur sur GET, j’utilise aussi ?_method=GET comme solution de contournement. Cependant, comme cela déclenche le 3 /,.__, je transmets un objet factice sous forme de données POST codées. Ce qui signifie que mon service doit ignorer les données publiées factices sur une requête ?_method=GET.

Crucial à ce stade de savoir sur 2 /. Cela m'a fait perdre beaucoup de temps.

J'ai intégré toute cette gestion dans une nouvelle classe RESTService avec prise en charge du balisage MXML, de sorte qu'il est possible de prétendre que cela n'existe pas côté client.

J'espère que ça aide quelqu'un.

9
verveguy

Cela m'a vraiment aidé! Merci! J'utilise Flex Builder 3

Remarque: les en-têtes de propriété de WebService sont en lecture seule ..__ alors j'ai essayé d'utiliser httpHeaders. Ça marche!

    var encoder:Base64Encoder = new Base64Encoder();
    encoder.insertNewLines = false;
    encoder.encode("test:test");

    sfWS.httpHeaders = {Authorization:"Basic " + encoder.toString()};   
1
user189100

Les méthodes setCredentials () et setRemoteCredentials () sont destinées à être utilisées avec Flex/LiveCycle Data Services. Elles ne sont donc probablement pas applicables dans votre cas.

Cela devrait fonctionner pour vous. J'ai pu reproduire ce problème sur mon serveur et ce correctif semble avoir fait l'affaire; cela semble toujours un peu bizarre, ce n'est pas plus convivial avec l'API, compte tenu de la fréquence d'utilisation d'un cas d'utilisation, mais néanmoins, j'ai testé et vérifié que cela fonctionne avec un certificat SSL valide:

private function authAndSend(service:HTTPService):void
{
        var encoder:Base64Encoder = new Base64Encoder();
        encoder.encode("someusername:somepassword");

        service.headers = {Authorization:"Basic " + encoder.toString()};                            
        service.send();
}

J'espère que ça aide! Et merci pour votre commentaire - je suis sûr que j’aurais moi-même rencontré celui-ci tôt ou tard. ;)

1
Christian Nunciato

J'ai eu le même problème en consommant HTTP Basic Authenticated Webservice. C'est ma solution. ça fonctionne 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();
}

usage 

authAndSend(WebService( aWebServiceWrapper.serviceControl));
1
user576241

En outre, afin que les autres utilisateurs ne passent pas 10 minutes à comprendre pourquoi l'exemple correct ne fonctionne pas correctement, vous devez importer le package mx.utils.Base64Encoder, par exemple:

        import mx.utils.Base64Encoder;

Au début ou quelque part dans la zone CDATA. Je suis novice en flexion, donc ce n'était pas évident au début.

0
Bradley Falzon

Essayez d’utiliser setCredentials plutôt que setRemoteCredentials et à défaut, utilisez Fiddler/Charles pour déterminer les en-têtes envoyés avec la demande.

0
Richard Szalay

Voici comment c'est fait.

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()}; 
0
Blake