【问题标题】:403 error when trying to access Google Authsub from FLash Application (Authsub for Actionscript)尝试从 FLash 应用程序访问 Google Authsub 时出现 403 错误(Actionscript 的 Authsub)
【发布时间】:2011-02-01 22:32:49
【问题描述】:

我正在尝试使用此处的说明让我的 Flex 应用程序通过 google 进行身份验证:

http://code.google.com/apis/gdata/docs/as-authsub.html

我已经复制了那里的示例,并试图让它工作。我在本地服务器上运行我的应用程序,所以我更改了下一个参数:

authSubParams['next'] = 'http://localhost/AuthSub.html';

获取第一个令牌工作正常,但是当我尝试获取长寿命令牌时出现错误:

getLongLivedToken: singleUseToken: 1%2Fa...
onHttpStatus: [HTTPStatusEvent type="httpStatus" bubbles=false cancelable=false eventPhase=2 status=403 responseURL=null]
onGetTokenFailed: Error #2032: Stream Error. URL: https://accounts.googleapis.com/accounts/AuthSubSessionToken

我似乎遇到了 403 错误。有什么想法吗?

整个应用程序:

<?xml version="1.0" encoding="utf-8"?>
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    minWidth="955" 
    minHeight="600"
    initialize=" onInitialized() "
    applicationComplete=" onLoaded() "
    >

    <fx:Script>
        <![CDATA[

            import flash.external.ExternalInterface;
            import flash.net.navigateToURL;

            import mx.controls.Alert;

            private function onInitialized() : void {
                // Load the cross domain policy file for each of the googleapis.com
                // domains used. At the very least, we need the ones for the API (photos)
                // and the one for AuthSub for ActionScript (accounts).
                Security.loadPolicyFile('http://photos.googleapis.com/data/crossdomain.xml');
                Security.loadPolicyFile('https://accounts.googleapis.com/crossdomain.xml');
            }

            private function onLoaded() : void {
                // Once the application has loaded, check to see if an AuthSub token was
                // placed into the current page's URL. If it was, the user has already
                // authenticated, we can continue to connect to the the service itself.
                // In a real application, the long-term cookie would also be stored and 
                // checked here, to remove the need for the user to authenticate for this 
                // application every time it is used.
                var searchPortion : String = ExternalInterface.call('window.location.search.toString');

                //searchPortion = "?token=tokenSavenFromPreviousAttempt";

                if (searchPortion.length > 0) {
                    // remove the ? from the token and extract the token.
                    searchPortion = searchPortion.substring(1);

                    // NOTE: Real applications should parse the URL properly.
                    if (searchPortion.indexOf('token=') == 0) {

                        log( "token found: " + searchPortion );

                        getLongLivedToken(searchPortion.substring(6));
                        return;
                    }
                }

                // No token found; redirect the user to the AuthSub page. Note that this URL
                // is on the google.com domain. We can contact the google.com domain because
                // this isn't a request from within Flash, but rather a page redirect.
                var getTokenPage : URLRequest = new URLRequest('https://www.google.com/accounts/AuthSubRequest');

                // Construct the parameters of the AuthSub request. These are the same parameters
                // as normal AuthSub, which can be found here: http://code.google.com/apis/accounts/docs/AuthSub.html#AuthSubRequest
                var authSubParams : URLVariables = new URLVariables();
                authSubParams['scope'] = 'http://photos.googleapis.com/data'; // photos API
                authSubParams['session'] = 1; // single-use token
                authSubParams['secure'] = 0; // non-secure apps
                authSubParams['next'] = 'http://localhost/AuthSub.html'; // The URL of this app.
                //authSubParams['next'] = 'http://localhost/'; // The URL of this app.

                log( "token not found, sending AuthSubRequest" );

                getTokenPage.data =  authSubParams;
                navigateToURL(getTokenPage, '_top');
            }

            private function getLongLivedToken(singleUseToken : String) : void {
                // Construct a call to the AuthSub for ActionScript endpoint on accounts.googleapis.com.
                // This call will exchange the single use token given to use by AuthSub for a long-term
                // token that we can use to make requests to endpoints such as Photos.
                var getTokenRequest : URLRequest = new URLRequest('https://accounts.googleapis.com/accounts/AuthSubSessionToken');

                // Due to a bug in Flash, a URLRequest with a GET request will
                // not properly send headers. We therefore use POST for this and *ALL*
                // requests.
                getTokenRequest.method = URLRequestMethod.POST;

                // Due to a bug in Flash, a URLRequest without a valid parameter will
                // not properly send headers. We therefore add a useless parameter to
                // make this code work.
                getTokenRequest.data = new URLVariables('pleaseignore=ignore');

                // Add the AuthSub for ActionScript headers.
                getTokenRequest.requestHeaders.push(new URLRequestHeader('Authorization', 'AuthSub token="' + singleUseToken + '"'));

                // Create the loader to get the token itself. The loader will callback
                // to the following event handlers if and when the server responds.
                var getToken : URLLoader = new URLLoader();
                getToken.addEventListener(Event.COMPLETE, onGetTokenResult);
                getToken.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onGetTokenFailed);
                getToken.addEventListener(IOErrorEvent.IO_ERROR, onGetTokenFailed);
                getToken.addEventListener( HTTPStatusEvent.HTTP_STATUS, onHttpStatus );

                log( "getLongLivedToken: singleUseToken: " + singleUseToken );

                try {
                    getToken.load(getTokenRequest);
                } catch (e : Error) {

                    log( "error:\n" + e.message );

                    Alert.show('Some error occurred: ' + e);

                }
            }

            private function onGetTokenResult(e : Event) : void {


                // Load the parameters from the response.
                var getToken : URLLoader = URLLoader(e.target);
                var params : URLVariables = new URLVariables(getToken.data);


                // Parse the session token from the result. Real applications
                // might at this point store the token in a long-term cookie so
                // that repeated usages of the application do not require this entire
                // authentication process.
                var sessionToken : String = params.Token;

                log( "onGetTokenResult: sessionToken: " + sessionToken );

                // Trim the newline from the end of the session token.
                sessionToken = sessionToken.substring(0, sessionToken.length - 1);

                Alert.show('session token: [' + sessionToken + ']');

                // Prepare a request to the photos API for the private album
                // of the user.
                var albumRequest : URLRequest = new URLRequest('http://photos.googleapis.com/data/feed/api/user/default');
                albumRequest.data = new URLVariables('access=private&amp;v=2&amp;err=xml');

                // Due to a bug in Flash, a URLRequest with a GET request will
                // not properly send headers. We therefore use POST for this and *ALL*
                // requests.
                albumRequest.method = URLRequestMethod.POST;

                var authsubHeader : String = 'AuthSub token="' + sessionToken + '"';

                // Add the Authorization header which uses the session token.
                albumRequest.requestHeaders.push(new URLRequestHeader('Authorization', authsubHeader));

                // The X-HTTP-Method-Override header tells the Photos API to treat this request
                // as a GET request, even though it is being conducted as a POST (due to the bug
                // mentioned above). This is very important, as GData APIs will react differently
                // to different HTTP request types.
                albumRequest.requestHeaders.push(new URLRequestHeader('X-HTTP-Method-Override', 'GET'));

                // We expect ATOM XML to be returned.
                albumRequest.requestHeaders.push(new URLRequestHeader('Content-Type', 'application/atom+xml'));

                var getAlbum : URLLoader = new URLLoader();
                getAlbum.addEventListener(Event.COMPLETE, onGetAlbumResult);
                getAlbum.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onGetAlbumFailed);
                getAlbum.addEventListener(IOErrorEvent.IO_ERROR, onGetAlbumFailed);

                try {
                    getAlbum.load(albumRequest);
                } catch (e : Error) {
                    Alert.show('Some error occurred: ' + e);  
                }
            }

            private function onGetAlbumResult(e : Event) : void {
                // Load the XML from the response.
                var getAlbum : URLLoader = URLLoader(e.target);
                Alert.show('Returned XML: ' + getAlbum.data);
            }

            private function onGetTokenFailed(e : ErrorEvent) : void {
                log( "onGetTokenFailed: " + e.text );
                Alert.show('Some error occurred: ' + e);
            }

            private function onGetAlbumFailed(e : ErrorEvent) : void {
                log( "onGetAlbumFailed: " + e.text );
                Alert.show('Some error occurred: ' + e);
            }

            private function onHttpStatus(e : HTTPStatusEvent) : void {
                log( "onHttpStatus: " + e );
                Alert.show('Some error occurred: ' + e);
            }

            private function log( message : String ) : void
            {
                trace( message );

                debugOutput.text = debugOutput.text ? debugOutput.text : "";

                debugOutput.text = debugOutput.text.length == 0 ? message : debugOutput.text + "\n" + message; 
            }

        ]]>
    </fx:Script>

    <s:TextArea
        id="debugOutput"
        left="5"
        right="5"
        top="5"
        bottom="5"
        />

</s:Application>

【问题讨论】:

    标签: apache-flex authsub


    【解决方案1】:

    变化:

    var searchPortion : String = ExternalInterface.call('window.location.search.toString');
    

    var searchPortion : String = decodeURIComponent( ExternalInterface.call('window.location.search.toString'));
    

    【讨论】:

      【解决方案2】:

      私有函数 onLoaded() : void { // 加载应用程序后,检查是否有 AuthSub 令牌 // 放入当前页面的 URL。如果是,则用户已经 // 认证后,我们可以继续连接到服务本身。 // 在真实的应用程序中,长期 cookie 也会被存储并且 // 在此处选中,以消除用户对此进行身份验证的需要 // 每次使用时的应用程序。 var searchPortion : String = ExternalInterface.call('window.location.search.toString');

      //searchPortion = "?token=tokenSavenFromPreviousAttempt";

      if (searchPortion.length > 0) { // 去除 ?从令牌中提取令牌。 searchPortion = searchPortion.substring(1);

      // 注意:真正的应用程序应该正确解析 URL。 if (searchPortion.indexOf('token=') == 0) {

        log( "token found: " + searchPortion );
      
        getLongLivedToken(searchPortion.substring(6));
        return;
      

      } }

      token 未正确解析。利用 var token:String = Application.application.parameters["token"]; 而是;

      【讨论】:

        猜你喜欢
        • 2011-09-09
        • 2011-08-22
        • 2012-03-29
        • 2023-03-30
        • 2011-04-15
        • 2016-04-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多