objective-c - google - endpoints framework
Google App Engine con interfaz ClientLogin para Objective-C (7)
Estoy experimentando el mismo problema en esta publicación anterior de stackoverflow.com .
Específicamente, parece que puedo obtener el token "Auth" correctamente, pero intento usarlo en el encabezado cuando accedo a las páginas posteriores, solo me devuelven el HTML de la página de inicio de sesión.
Siguiendo los enlaces relacionados con esta publicación, he determinado que debe realizar una llamada posterior a esta URL .
Una llamada a la URL le proporcionará una cookie ACSID que luego deberá pasar en llamadas posteriores para mantener un estado autenticado.
Al solicitar esta cookie, he leído varias publicaciones que indican que debes especificar tu token de autenticación original adjuntándolo a la cadena de consulta de modo que:
?auth=this_is_my_token
También he leído que debe configurarlo en el encabezado http, tal como se describe en la documentación de google, de modo que un nombre / valor del encabezado http sea:
Authorization: GoogleLogin auth=yourAuthToken
Intenté ambos enfoques y no veo que se devuelvan las cookies. He usado Wireshark, LiveHttpHeaders para Firefox y simples declaraciones NSLog tratando de ver si se devuelve algo como esto.
A continuación se muestra el fragmento de código que he estado usando.
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);
}
Espero que pueda usar ClientLogin
para el ClientLogin
de Google App Engine.
Vea el código que hace esto en el SDK oficial. La última versión de SDK incluso lo ha dividido en su propio archivo .
Agregué un código de muestra a esta pregunta porque alguien me contactó directamente sobre mi solución. Tenga en cuenta que debe establecer el parámetro "servicio" igual a "ah" en la solicitud del token inicial.
Solicitud inicial de token [hecho sincrónicamente] NOTA: el parámetro "servicio" está configurado en "ah" y la "fuente" simplemente está configurada en "myapp", debe usar el nombre de su aplicación.
//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
};
El siguiente paso es hacer que su aplicación se ejecute en el motor de la aplicación de Google para darle la cookie ASCID. No estoy seguro de por qué hay este paso adicional, parece ser un problema al final de Google y, probablemente, por qué GAE no se encuentra actualmente en la lista de la API api-c google api. Mis pruebas muestran que debo solicitar la cookie para sincronizar con GAE. Además, note que no hago nada con la cookie. Parece que solo solicitándolo y cocinándose, las solicitudes futuras contendrán automáticamente la cookie. No estoy seguro si esto es una cosa de iphone porque mi aplicación es una aplicación de iPhone pero no entiendo completamente qué está pasando con esta cookie. NOTA: el uso de "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];
Finalmente, puedo publicar json en mi aplicación Gae. NOTA: el fragmento a continuación es una solicitud asíncrona. Podemos manejar las respuestas implementando 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");
}
Primero, gracias por la excelente publicación que realmente me ayudó a comenzar.
2 ° - He estado peleando con mi aplicación, tratando de enviar POST al GAE mientras estoy autenticado.
Esta es la solicitud que se genera al realizar la POSTING, una vez que haya adquirido 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
Tenga en cuenta que Google ha cambiado recientemente la forma en que se indica el error de autorización. Solían colocar un token de Error en la respuesta. Ahora solo devuelven un estado 403 (Prohibido). ¡Esto rompió mi código!
Usar HOSTED_OR_GOOGLE es incorrecto, y explicaré por qué.
Hay dos tipos de cuentas en el mundo de Google. Los que creas para GMail, etc. son cuentas de "Google". Los que crea para Apps for Domains son cuentas "Hosted". Puede usar un correo electrónico de cuenta alojada para crear una cuenta de Google, creando así una dirección de correo electrónico asociada a ambos tipos de cuentas.
Su aplicación Google App Engine se puede configurar para que funcione con (1) Cuentas de Google o (2) Cuentas alojadas para un dominio en particular.
Supongamos que estamos desarrollando una aplicación para cuentas de Google. Un usuario ingresa una dirección de correo electrónico asociada con una cuenta de Google y una cuenta alojada. Google usará su cuenta de Google para el inicio de sesión. Todo esto funciona bien
Ahora, si usamos ClientLogin con esta misma dirección de correo electrónico y usamos HOSTED_OR_GOOGLE para el tipo de cuenta, el inicio de sesión será exitoso, pero usará la cuenta alojada, ya que la cuenta alojada tiene prioridad. Como mencioné anteriormente, no puede usar una cuenta alojada para una aplicación que espera una cuenta de Google. Entonces la autenticación no funcionará.
Por lo tanto, al usar ClientLogin para autenticarse con una aplicación de Google App Engine, debe usar GOOGLE para el tipo de cuenta si la aplicación es para cuentas de Google o HOSTED para el tipo de cuenta si la aplicación es para un dominio.
Creé algunas clases obj-c para implementar ClientLogin, incluida la compatibilidad con Google App Engine:
Gracias por esta publicación y especialmente por la respuesta de Keith pero no funciona para mí. Incluso si parece estar bien para mí ... muy extraño.
Compruebo esta publicación ( ¿Cómo accedes a un servicio autenticado de Google App Engine desde un cliente python (no web)? ) Que habla sobre hacer lo mismo en python. Lo pruebo y funciona.
Y el código objetivo C propuesto por Keith es realmente similar al código python.
Pero cuando trato de obtener el token "Auth", authData contiene Error = BadAuthentication.
Alguien tiene una idea sobre los posibles problemas?