我正在尝试让我的Flex应用程序使用google中的说明进行身份验证:
http://code.google.com/apis/gdata/docs/as-authsub.html
我在那里复制了这个例子,并试图让它发挥作用。我在loca服务器上运行我的应用程序,所以我更改了下一个参数:
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&v=2&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>
答案 0 :(得分:0)
变化:
var searchPortion : String = ExternalInterface.call('window.location.search.toString');
到
var searchPortion : String = decodeURIComponent( ExternalInterface.call('window.location.search.toString'));
答案 1 :(得分:0)
私有函数onLoaded():void { //加载应用程序后,检查是否有AuthSub令牌 //放入当前页面的URL。如果是,用户已经 //经过身份验证,我们可以继续连接到服务本身。 //在实际应用程序中,也会存储长期cookie //在此处选中,以消除用户对此进行身份验证的需要 //应用程序每次使用时。 var searchPortion:String = ExternalInterface.call('window.location.search.toString');
// searchPortion =“?token = tokenSavenFromPreviousAttempt”;
if(searchPortion.length&gt; 0){ // 除掉 ?从令牌中提取令牌。 searchPortion = searchPortion.substring(1);
//注意:真正的应用程序应该正确解析URL。 if(searchPortion.indexOf('token =')== 0){
log( "token found: " + searchPortion );
getLongLivedToken(searchPortion.substring(6));
return;
} }
令牌未正确解析。使用 var token:String = Application.application.parameters [“token”]; 代替;