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

发布于 2024-07-13 09:55:20 字数 2035 浏览 10 评论 0原文

我正在尝试从 Adob​​e 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).']

编辑: 经过 Adob​​e 的一些关注后,问题已解决。 请参阅下面的帖子以获得完整的解释。 此代码适用于任意长度的 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

も让我眼熟你 2024-07-20 09:55:20

终于得到了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.

甜`诱少女 2024-07-20 09:55:20

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

虽然您已经弄清楚如何在进行调用之前添加标头,但令人讨厌的事实是,在 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 requests

3/ 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.

初与友歌 2024-07-20 09:55:20

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

希望它有帮助! 感谢您发帖——我确信我自己迟早会遇到这个问题。 ;)

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:

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

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

Hope it helps! And thanks for posting -- I'm sure I would've run into this one sooner or later myself. ;)

悍妇囚夫 2024-07-20 09:55:20

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

一注意:WebService 的属性标头是只读的。
所以我尝试使用httpHeaders。 有用!

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

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

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!

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

    sfWS.httpHeaders = {Authorization:"Basic " + encoder.toString()};   
离线来电— 2024-07-20 09:55:20

我在使用 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));

I had the same problem while consuming HTTP Basic Authenticated Webservice. This is my solution; it works fine:

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));
还如梦归 2024-07-20 09:55:20

尝试使用 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.

半衬遮猫 2024-07-20 09:55:20

另外,这样其他人就不会花 10 分钟来弄清楚为什么 正确的示例不太有效,您需要导入 mx.utils.Base64Encoder 包,例如:

        import 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:

        import mx.utils.Base64Encoder;

At the beginning or somewhere within the CDATA area. I'm new to flex so this wasn't quite obvious at first.

枕花眠 2024-07-20 09:55:20

这就是它的完成方式。

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

This is how its done.

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()}; 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文