使用Adobe Flex / AIR中的HTTPService对象进行HTTP基本身份验证

时间:2009-01-29 07:53:37

标签: flex air http-authentication httpservice

我正在尝试从Adobe AIR应用程序中请求需要基本授权标头的HTTP资源。我尝试手动将标头添加到请求中,以及使用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" />

但是,仍会弹出标准的基本身份验证对话框,提示用户输入用户名和密码。我有一种感觉,我没有以正确的方式做到这一点,但我能找到的所有信息(Flex文档,博客,谷歌等)要么没有效果,要么太模糊,无法提供帮助。

任何黑魔法,哦Flex大师?感谢。


编辑:将setRemoteCredentials()更改为setCredentials()会产生以下ActionScript错误:

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

编辑:经过Adobe的一些关注后,问题解决了。有关完整说明,请参阅下面的帖子。此代码适用于任意长度的HTTP身份验证标头。

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

8 个答案:

答案 0 :(得分:13)

最后得到了Adobe的一些关注并得到了答案。长HTTP身份验证标头的问题是,默认情况下,Base64Encoder类将每72个字符注入换行符。显然,这会导致base-64编码字符串的一大块被解释为新的标头属性,从而导致错误。

您可以通过设置(在上面的示例中)encoder.insertNewLines = false来解决此问题。默认设置为true。

我已修复上述代码以适用于任意长的身份验证字符串。

答案 1 :(得分:9)

阿。痛苦,痛苦。纯粹的苦难。

虽然您已经想出如何在拨打电话之前添加标头,但令人讨厌的事实是,在Flash /浏览器集成空间的某个地方,您的标题会被重新删除。

去年在verveguy.blogspot.com

的博文中

所以我揭开了真相。 (我认为) 它比人们想象的更痛苦

1 /所有HTTP GET请求都被剥离了标头。它不在Flex堆栈中,因此它可能是底层的Flash播放器运行时

2 /所有内容类型不同于application/x-www-form-urlencoded的HTTP GET请求都会转为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 /。这浪费了我一大堆时间。

我已经将所有这些处理构建到一个支持MXML标记的新RESTService类中,因此可以假装它在客户端不存在。

希望这有助于某人。

答案 2 :(得分:1)

setCredentials()&amp; 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();
}

希望它有所帮助!感谢发帖 - 我相信我迟早会遇到这个问题。 ;)

答案 3 :(得分:1)

这对我有帮助!谢谢! 我使用Flex Builder 3

一个注意事项:WebService的属性头是只读的。 所以我尝试使用httpHeaders。它有效!

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

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

答案 4 :(得分:1)

我在使用HTTP基本身份验证Web服务时遇到了同样的问题。这是我的解决方案;它工作正常:

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));

答案 5 :(得分:0)

尝试使用setCredentials而不是setRemoteCredentials并使其失败,使用Fiddler / Charles查找与请求一起发送的标头。

答案 6 :(得分:0)

另外,为了让其他人花费10分钟来解决为什么correct example不能正常工作,你需要导入mx.utils.Base64Encoder包,例如:

        import mx.utils.Base64Encoder;

CDATA区域的开头或某处。我刚开始弯曲,所以一开始并不是很明显。

答案 7 :(得分:0)

这是它的完成方式。

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