10

我在之前的 stackoverflow.com 帖子中遇到了同样的问题。

具体来说,我似乎能够正确获取“Auth”令牌,但是当我访问后面的页面时尝试在标题中使用它仍然只是返回给我登录页面的 HTML。

通过与这篇文章相关的链接,我确定您需要对该 URL进行后续调用。

然后,对 URL 的调用将为您提供一个 ACSID cookie,然后需要在后续调用中传递该 cookie 以保持经过身份验证的状态。

在请求此 cookie 时,我已阅读各种帖子,说您需要通过将原始身份验证令牌附加到查询字符串来指定原始身份验证令牌,以便:

?auth=this_is_my_token

我还读到您应该按照google 文档中的说明在 http 标头中设置它,以便 http 标头名称/值是:

Authorization: GoogleLogin auth=yourAuthToken

我已经尝试了这两种方法,但没有看到任何返回的 cookie。我使用了 Wireshark、Firefox 的 LiveHttpHeaders 和简单的 NSLog 语句,试图查看是否返回了类似的内容。

下面是我一直在使用的代码片段。

NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:@"http://yourapp.appspot.com/_ah/login?auth=%@", [token objectForKey:@"Auth"]]];
NSHTTPURLResponse* response;
NSError* error;
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setValue:[NSString stringWithFormat:@"GoogleLogin auth=%@", [token objectForKey:@"Auth"]] forHTTPHeaderField:@"Authorization"];
NSData * data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];  

//show me all header fields
NSLog([[response allHeaderFields] description]);

//show me the response
NSLog(@"%@", [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease]);
NSArray * all = [NSHTTPCookie cookiesWithResponseHeaderFields:[response allHeaderFields] forURL:[NSURL URLWithString:@"http://yourapp.appspot.com/_ah/login"]];

//show me all cookies
for (NSHTTPCookie *cookie in all) 
{
    NSLog(@"Name: %@ : Value: %@", cookie.name, cookie.value); 
}

我希望您可以使用ClientLoginGoogle App Engine 代码。

4

7 回答 7

16

向此问题添加示例代码,因为有人直接就我的解决方案与我联系。请注意,您必须在初始令牌请求中将“服务”参数设置为等于“啊”。

Token 的初始请求 [同步完成] 注意:“service”参数设置为“ah”,“source”设置为“myapp”,您应该使用您的应用名称。

//create request
NSString* content = [NSString stringWithFormat:@"accountType=HOSTED_OR_GOOGLE&Email=%@&Passwd=%@&service=ah&source=myapp", [loginView username].text, [loginView password].text];
NSURL* authUrl = [NSURL URLWithString:@"https://www.google.com/accounts/ClientLogin"];
NSMutableURLRequest* authRequest = [[NSMutableURLRequest alloc] initWithURL:authUrl];
[authRequest setHTTPMethod:@"POST"];
[authRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-type"];
[authRequest setHTTPBody:[content dataUsingEncoding:NSASCIIStringEncoding]];

NSHTTPURLResponse* authResponse;
NSError* authError;
NSData * authData = [NSURLConnection sendSynchronousRequest:authRequest returningResponse:&authResponse error:&authError];  

NSString *authResponseBody = [[NSString alloc] initWithData:authData encoding:NSASCIIStringEncoding];

//loop through response body which is key=value pairs, seperated by \n. The code below is not optimal and certainly error prone. 
NSArray *lines = [authResponseBody componentsSeparatedByString:@"\n"];
NSMutableDictionary* token = [NSMutableDictionary dictionary];
for (NSString* s in lines) {
    NSArray* kvpair = [s componentsSeparatedByString:@"="];
    if ([kvpair count]>1)
        [token setObject:[kvpair objectAtIndex:1] forKey:[kvpair objectAtIndex:0]];
}

//if google returned an error in the body [google returns Error=Bad Authentication in the body. which is weird, not sure if they use status codes]
if ([token objectForKey:@"Error"]) {
    //handle error
};

下一步是让你的应用在谷歌应用引擎上运行,为你提供 ASCII cookie。我不确定为什么会有这个额外的步骤,这似乎是 google 的一个问题,可能是为什么 GAE 目前不在他们列出的 obj-c google data api 库中。我的测试表明我必须请求 cookie 才能与 GAE 同步。另外,请注意我没有对 cookie 做任何事情。似乎只是通过请求它并获得 cookie,未来的请求将自动包含 cookie。我不确定这是否是 iphone 的事情,因为我的应用程序是 iphone 应用程序,但我不完全理解这个 cookie 发生了什么。注意:使用“myapp.appspot.com”。

NSURL* cookieUrl = [NSURL URLWithString:[NSString stringWithFormat:@"http://myapp.appspot.com/_ah/login?continue=http://myapp.appspot.com/&auth=%@", [token objectForKey:@"Auth"]]];
    NSLog([cookieUrl description]);
    NSHTTPURLResponse* cookieResponse;
    NSError* cookieError;
    NSMutableURLRequest *cookieRequest = [[NSMutableURLRequest alloc] initWithURL:cookieUrl];

    [cookieRequest setHTTPMethod:@"GET"];

    NSData* cookieData = [NSURLConnection sendSynchronousRequest:cookieRequest returningResponse:&cookieResponse error:&cookieError];   

最后,我可以将 json 发布到我的 gae 应用程序中。注意:下面的代码片段是一个异步请求。我们可以通过实现 didReceiveResponse、didReceiveData、didFailWIthError 来处理响应。

NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:@"http://myapp.appspot.com/addRun?auth=%@", mytoken]];
    NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:url];
    [request setHTTPMethod:@"POST"];
    [request setHTTPBody:@"my http body";

    NSURLConnection *connectionResponse = [[NSURLConnection alloc] initWithRequest:request delegate:self];
    if (!connectionResponse) {
        NSLog(@"Failed to submit request");
    } else {
        NSLog(@"Request submitted");
    }
于 2009-01-26T01:08:05.990 回答
1

查看官方 SDK 中执行此操作的代码。最新的 SDK 版本甚至将其拆分为自己的文件

于 2009-01-23T19:22:15.323 回答
1

1st - 感谢这篇很棒的帖子,它真的让我开始了。

第二 - 我一直在用我的应用程序解决它,试图在经过身份验证的情况下发布到 GAE。

这是在 POST 时构建的请求,一旦您获得了 authtoken:

    NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];


[request setURL:[NSURL URLWithString:url]];
[request setHTTPMethod:@"POST"];
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
[request setValue:@"image/png" forHTTPHeaderField:@"Content-Type"];
[request setHTTPBody:postData];

[request setValue:authtoken forHTTPHeaderField:@"auth"];  // <-- the magic
  • 马特布
于 2009-02-28T02:48:01.537 回答
1

我创建了一些 obj-c 类来实现 ClientLogin,包括对 Google App Engine 的支持:

http://github.com/cameronr/GoogleAppEngineAuth

于 2010-03-08T22:58:48.483 回答
0

请注意,Google 最近更改了指示授权失败的方式。他们过去常常在响应中放置一个错误标记。现在他们只返回 403(禁止)状态。这破坏了我的代码!

于 2009-12-03T15:11:13.453 回答
0

感谢这篇文章,尤其是 Keith 的回答,但它对我不起作用。即使对我来说似乎还可以……很奇怪。

我查看了这篇文章(How do you access an authenticated Google App Engine service from a (non-web) python client?),它谈到了在 python 中做同样的事情。我测试它并且它有效。

并且 Keith 提出的客观 C 代码与 python 代码非常相似。

但是当我尝试获取“Auth”令牌时,authData 包含 Error=BadAuthentication。

有人对可能的问题有所了解?

于 2010-02-19T22:13:41.050 回答
0

使用 HOSTED_OR_GOOGLE 是错误的,我会解释原因。

Google 世界中有两种帐户。您为 GMail 等创建的那些是“Google”帐户。您为域应用程序创建的那些是“托管”帐户。您可以使用托管帐户电子邮件来创建 Google 帐户,从而创建与这两种帐户相关联的电子邮件地址。

您的 Google App Engine 应用可以配置为使用 (1) Google 帐户或 (2) 特定域的托管帐户。

假设我们正在为 Google 帐户开发一个应用程序。用户输入与 Google 帐户和托管帐户关联的电子邮件地址。Google 将使用他们的 Google 帐户进行登录。这一切都很好。

现在,如果我们使用具有相同电子邮件地址的 ClientLogin 并使用 HOSTED_OR_GOOGLE 作为帐户类型,登录将成功,但它将使用托管帐户,因为托管帐户优先。正如我上面提到的,您不能将托管帐户用于需要 Google 帐户的应用程序。所以认证将不起作用。

因此,当使用 ClientLogin 对 Google App Engine 应用程序进行身份验证时,如果应用程序用于 Google 帐户,则需要使用 GOOGLE 作为帐户类型,如果应用程序用于域,则需要使用 HOSTED 作为帐户类型。

于 2010-03-06T12:56:13.140 回答