Adobe Flex/AIR 中使用 HTTPService 对象进行 HTTP 基本身份验证
我正在尝试从 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();
}
I'm trying to request a HTTP resource that requires basic authorization headers from within an Adobe AIR application. I've tried manually adding the headers to the request, as well as using the setRemoteCredentials() method to set them, to no avail.
Here's the 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" />
However, a standard basic auth dialog box still pops up prompting the user for their username and password. I have a feeling I'm not doing this the right way, but all the info I could find (Flex docs, blogs, Google, etc.) either hasn't worked or was too vague to help.
Any black magic, oh Flex gurus? Thanks.
EDIT: Changing setRemoteCredentials() to setCredentials() yields the following ActionScript error:
[MessagingError message='Authentication not supported on DirectHTTPChannel (no proxy).']
EDIT: Problem solved, after some attention from Adobe. See the posts below for a full explanation. This code will work for HTTP Authentication headers of arbitrary length.
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();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
终于得到了Adobe的一些关注,并得到了对此的答复。 长 HTTP 身份验证标头的问题在于,默认情况下,Base64Encoder 类将每 72 个字符注入换行符。 显然,这会导致一大块 Base-64 编码字符串被解释为新的标头属性,从而导致错误。
您可以通过设置(在上面的示例中)
encoder.insertNewLines = false;
来修复此问题,默认设置为 true。我已修复上述代码以适用于任意长的身份验证字符串。
Finally received some attention from Adobe and got an answer on this. The problem with long HTTP Authentication headers is that, by default, the Base64Encoder class will inject newline characters every 72 characters. Obviously that causes a chunk of the base-64 encoded string to be interpreted as a new header attribute, which causes the error.
You can fix this by setting (in the above example)
encoder.insertNewLines = false;
The default setting is true.I've fixed the above code to work for arbitrarily long Authentication strings.
啊。 痛苦,苦难。 纯粹的痛苦。
虽然您已经弄清楚如何在进行调用之前添加标头,但令人讨厌的事实是,在 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 类中,因此可以假装这在客户端不存在。
希望这对某人有帮助。
Ah. The pain, the suffering. The sheer misery.
While you've figured out how to add a header before making your call, the nasty truth is that somewhere deep down in the Flash/browser integration space your headers are being removed again.
From my blogpost last year at verveguy.blogspot.com
So I have unraveled the Truth. (I think)
It's more tortured than one would imagine
1/ All HTTP GET requests are stripped of headers. It's not in the Flex stack so it's probably the underlying Flash player runtime
2/ All HTTP GET requests that have content type other than
application/x-www-form-urlencoded
are turned into POST requests3/ All HTTP POST requests that have no actual posted data are turned into GET requests. See 1/ and 2/
4/ All HTTP PUT and HTTP DELETE requests are turned into POST requests. This appears to be a browser limitation that the Flash player is stuck with. (?)
What this boils down to in practical terms is that if you want to pass headers in all requests, you should always use POST and you should find another way to communicate the semantics of the operation you "really wanted". The Rails community have settled on passing
?_method=PUT/DELETE
as a work around for the browser problems underlying 4/Since Flash adds the wonderful header stripping pain on GET, I'm also using
?_method=GET
as a workaround for that. However, since this trips up on 3/,I am passing a dummy object as the encoded POST data. Which means my service needs to ignore dummy posted data on a
?_method=GET
request.Crucial at this point to know about 2/. That wasted a bunch of my time.
I've built all of this handling into a new RESTService class with MXML markup support so it's possible to pretend this doesn't exist on the client side.
Hope this helps someone.
setCredentials() & setRemoteCredentials() 方法旨在与 Flex/LiveCycle Data Services 一起使用,因此它们可能不适用于您的情况。
这应该对你有用。 我能够在我的服务器上重现此行为,并且此修复似乎已经成功; 考虑到您认为它是多么常见的用例,这似乎仍然有点奇怪,这对 API 用户不友好,但尽管如此,我已经测试并验证了它的工作原理,并给出了有效的 SSL 证书:
希望它有帮助! 感谢您发帖——我确信我自己迟早会遇到这个问题。 ;)
The setCredentials() & setRemoteCredentials() methods are intended for use with Flex/LiveCycle Data Services, so they probably don't apply in your case.
This ought to work for you. I was able to reproduce this behavior on my server, and this fix seems to have done the trick; it still seems a bit odd this isn't more API-user-friendly, considering how common a use case you'd think it were, but nonetheless, I've tested and verified this works, given a valid SSL cert:
Hope it helps! And thanks for posting -- I'm sure I would've run into this one sooner or later myself. ;)
这确实对我有帮助! 谢谢!
我使用 Flex Builder 3
一注意:WebService 的属性标头是只读的。
所以我尝试使用httpHeaders。 有用!
This really has helped me! Thanks!
I use Flex Builder 3
One note: WebService's property headers is read only.
So I tried to use httpHeaders. It works!
我在使用 HTTP Basic Authenticated Webservice 时遇到了同样的问题。 这是我的解决方案; 它工作正常:
用法
I had the same problem while consuming HTTP Basic Authenticated Webservice. This is my solution; it works fine:
usage
尝试使用 setCredentials 而不是 setRemoteCredentials,如果失败,请使用 Fiddler/Charles 找出随请求发送的标头。
Try using setCredentials rather than setRemoteCredentials and failing that, using Fiddler/Charles to find out what headers are being sent with the request.
另外,这样其他人就不会花 10 分钟来弄清楚为什么 正确的示例不太有效,您需要导入 mx.utils.Base64Encoder 包,例如:
在开头或 CDATA 区域内的某个位置。 我是 Flex 新手,所以一开始这并不是很明显。
Also, just so other people don't spend 10 minutes working out why the correct example doesn't quite work asis, you need to import the mx.utils.Base64Encoder package eg:
At the beginning or somewhere within the CDATA area. I'm new to flex so this wasn't quite obvious at first.
这就是它的完成方式。
This is how its done.