在 Adobe Flex/AIR 中使用 HTTPService 对象进行 HTTP 基本身份验证
Posted
技术标签:
【中文标题】在 Adobe Flex/AIR 中使用 HTTPService 对象进行 HTTP 基本身份验证【英文标题】:HTTP Basic Authentication with HTTPService Objects in Adobe Flex/AIR 【发布时间】:2010-10-04 04:45:18 【问题描述】:我正在尝试从 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 文档、博客、Google 等)要么没有用,要么太模糊,无法提供帮助。
任何黑魔法,哦,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();
【问题讨论】:
【参考方案1】:终于得到了Adobe的关注并得到了答复。长 HTTP 身份验证标头的问题在于,默认情况下,Base64Encoder 类将每 72 个字符注入换行符。显然,这会导致一段 base-64 编码字符串被解释为新的标头属性,从而导致错误。
您可以通过设置(在上面的示例中)encoder.insertNewLines = false;
来解决此问题,默认设置为 true。
我已将上述代码修复为适用于任意长度的身份验证字符串。
【讨论】:
哇,谈论一个非常可怕的默认值。这垃圾是谁写的!?【参考方案2】:我在使用 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));
【讨论】:
【参考方案3】:这就是它的完成方式。
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();
【讨论】:
【参考方案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】:啊。痛苦,苦难。纯粹的苦难。
虽然您已经知道如何在拨打电话之前添加标头,但令人讨厌的事实是,在 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/ 至关重要。这浪费了我很多时间。
我已将所有这些处理构建到一个新的 RESTService 类中,并支持 MXML 标记,因此可以假装它在客户端不存在。
希望这对某人有所帮助。
【讨论】:
【参考方案6】:另外,为了让其他人不用花 10 分钟时间弄清楚为什么 correct example 不能正常工作,您需要导入 mx.utils.Base64Encoder 包,例如:
import mx.utils.Base64Encoder;
在 CDATA 区域的开头或某处。我是 flex 新手,所以一开始这并不是很明显。
【讨论】:
好收获。我已经更新了问题中的代码以反映缺少的导入,谢谢!【参考方案7】:setCredentials() 和 setRemoteCredentials() 方法旨在用于 Flex/LiveCycle 数据服务,因此它们可能不适用于您的情况。
这应该对你有用。我能够在我的服务器上重现这种行为,而且这个修复似乎成功了;考虑到您认为它是多么常见的用例,这似乎仍然有点奇怪,这不是对 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();
希望对您有所帮助!感谢您的发帖——我相信我自己迟早会遇到这个。 ;)
【讨论】:
啊,谢谢,这更有意义。我仍然有问题,因为这段代码给了我一个“错误 #2096:HTTP 请求标头基本尝试使用 setCredentials 而不是 setRemoteCredentials,如果失败,请使用 Fiddler/Charles 找出随请求发送的标头。
【讨论】:
fiddler/charles 的输出是什么?以上是关于在 Adobe Flex/AIR 中使用 HTTPService 对象进行 HTTP 基本身份验证的主要内容,如果未能解决你的问题,请参考以下文章