Подтвердить что ты не робот

Google App Engine с интерфейсом ClientLogin для Objective-C

У меня такая же проблема в этом предыдущем postoffflow.com post.

В частности, я, похоже, могу правильно получить токен "Auth", но попытки использовать его в заголовке при доступе к более поздним страницам все равно возвращают мне HTML-страницу входа.

Следуя ссылкам, связанным с этим сообщением, я решил, что вам нужно сделать следующий вызов этого URL.

Затем вызов URL-адреса даст вам файл cookie ACSID, который затем должен быть передан в последующих вызовах, чтобы поддерживать аутентифицированное состояние.

При запросе этого файла cookie я прочитал разные сообщения, в которых вам нужно указать ваш оригинальный токен аутентификации, добавив его в строку запроса, чтобы:

?auth=this_is_my_token

Я также прочитал, что вы должны установить его в заголовке http, как описано в документации Google, чтобы имя/значение заголовка http:

Authorization: GoogleLogin auth=yourAuthToken

Я пробовал оба подхода и не вижу возвращенных файлов cookie. Я использовал Wireshark, LiveHttpHeaders для Firefox и простые инструкции 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); 
}

Надеюсь, вы можете использовать ClientLogin для кода Google App Engine.

4b9b3361

Ответ 1

Добавление примерного кода к этому вопросу, потому что кто-то связался со мной напрямую о моем решении. Обратите внимание, что вы должны установить параметр "service" равным "ah" в первоначальном запросе маркера.

Исходный запрос на токен [выполняется синхронно] ПРИМЕЧАНИЕ. Параметр "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
};

Следующий шаг - заставить ваше приложение работать с движком Google, чтобы предоставить вам файл cookie ASCID. Я не уверен, почему есть этот дополнительный шаг, кажется, проблема в конце google и, вероятно, почему GAE в настоящее время не находится в их списке obj-c google data api library. Мои тесты показывают, что я должен запросить cookie для синхронизации с GAE. Кроме того, заметьте, я ничего не делаю с файлом cookie. Кажется, что, запросив его и получая cookie, будущие запросы будут автоматически содержать cookie. Я не уверен, что это приложение iphone. Bc мое приложение - приложение для 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");
    }

Ответ 2

Проверьте код, который делает это в официальном SDK. Последняя версия SDK даже разбила на собственный файл.

Ответ 3

1-й - спасибо за отличный пост, он действительно начал меня.

2nd. Я пробовал его с помощью своего приложения, пытаясь выполнить POST на GAE во время проверки подлинности.

Это запрос создается, когда POSTing, как только вы приобрели 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
  • mattb

Ответ 5

Обратите внимание, что Google недавно изменил способ отказа авторизации. Они использовали для размещения маркера ошибки в ответе. Теперь они просто возвращают 403 (Запрещенный) статус. Это сломало мой код!

Ответ 6

Спасибо за этот пост и особенно ответ от Кита, но он не работает для меня. Даже если это кажется мне хорошо... очень странно.

Я проверяю этот пост (Как получить доступ к аутентифицированному сервису Google App Engine от клиента (не веб-сайта) python?), который говорит о том, чтобы делать то же самое в python. Я тестирую его, и он работает.

И объектный C-код, предложенный Кейтом, действительно похож на код python.

Но когда я пытаюсь получить authData-маркер Auth, содержит Error = BadAuthentication.

Кто-нибудь получил представление о возможных проблемах?

Ответ 7

Использование HOSTED_OR_GOOGLE неверно, и я объясню, почему.

В мире Google существует два типа аккаунтов. Те, которые вы создаете для GMail и т.д., Являются учетными записями Google. Те, которые вы создаете для приложений для доменов, являются учетными записями "Хостинг". Вы можете использовать электронную почту Hosted Account, чтобы создать учетную запись Google, тем самым создав адрес электронной почты, связанный с обоими типами учетных записей.

Приложение Google App Engine можно настроить для работы с (1) учетными записями Google или (2) хостинговыми учетными записями для определенного домена.

Предположим, что мы разрабатываем приложение для учетных записей Google. Пользователь вводит адрес электронной почты, связанный с учетной записью Google и хостинговой учетной записью. Google будет использовать свою учетную запись Google для входа в систему. Все это прекрасно работает.

Теперь, если мы используем ClientLogin с этим же адресом электронной почты и используем HOSTED_OR_GOOGLE для типа учетной записи, логин будет успешным, но он будет использовать Hosted Account, так как Hosted Account имеет приоритет. Как я уже упоминал выше, вы не можете использовать Hosted Account для приложения, которое ожидает учетную запись Google. Таким образом, аутентификация не будет работать.

Таким образом, при использовании ClientLogin для аутентификации с помощью приложения Google App Engine вам нужно использовать GOOGLE для типа учетной записи, если приложение предназначено для учетных записей Google, или ХОСТИРОВАНО для типа учетной записи, если приложение предназначено для домена.