retrieve gmail address on login using GTMOAuth2

2019-06-09 13:50发布

问题:

I am using GTMOAuth2 for login on iOS with my enterprise app. Scenario is only users with account @mycompanyname.com can sign in.

The problem is I am calling the method that is provided by the documentation, but I am unable to retrieve the user's email account that he used to sign in.

The call on sign in is made as follows:

_auth = [self authForGoogle];

// Display the authentication view
GTMOAuth2ViewControllerTouch * viewController = [[GTMOAuth2ViewControllerTouch alloc] initWithAuthentication:_auth
                                                                                            authorizationURL:[NSURL URLWithString:GoogleAuthURL]
                                                                                            keychainItemName:@"GoogleKeychainName"
                                                                                                    delegate:self
                                                                                            finishedSelector:@selector(viewController:finishedWithAuth:error:)];
[_window setRootViewController: viewController];
[_window makeKeyAndVisible];

In my delegate method of the GTMOAuth2 I did this to try to retrieve the email address:

- (void)viewController:(GTMOAuth2ViewControllerTouch * )viewController
  finishedWithAuth:(GTMOAuth2Authentication * )auth
             error:(NSError * )error
{
if ([[_auth userEmail] rangeOfString:@"@mycompanyname.com"].location == NSNotFound && error != nil ) {
    // Loop for no mycompanyname mail domain and also error in login
    NSLog(@"Loop 1 - Non mycompanyname domain email OR Google login error.");
    UIAlertView * alert = [[UIAlertView alloc] initWithTitle:@"Error"
                                                     message:@"Please Login with your mycompanyname email."
                                                    delegate:nil
                                           cancelButtonTitle:@"OK"
                                           otherButtonTitles:nil];
    [alert show];        
} else if ([[_auth userEmail] rangeOfString:@"@mycompanyname.com"].location == NSNotFound) {
    // Loop for no error in login but without mycompanyname mail domain
    NSLog(@"Loop 2 - Non mycompanyname domain email AND no Google login error.");

    UIAlertView * alert = [[UIAlertView alloc] initWithTitle:@"Authentication Denied"
                                                     message:@"Please Login with your mycompanyname email."
                                                    delegate:nil
                                           cancelButtonTitle:@"OK"
                                           otherButtonTitles:nil];
    [alert show];
} else if (error != nil) {
    NSLog(@"Loop 3 - mycompanyname domain email AND Google login error.");
    if ([[error localizedDescription] rangeOfString:@"error -1000"].location != NSNotFound)
    {
        NSLog(@"Loop 3.1 - Error message contains 'error -1000'.");
        // Loop to catch unwanted error message from GTMOAuth which will show if user enters the app and decides not to sign in but enters the app after again.
    } else
    {
        // Loop for error in authentication of user for google account
        NSLog(@"Loop 3.2 - Error message caused by no internet connection.");

        UIAlertView * alert = [[UIAlertView alloc] initWithTitle:@"Error"
                                                         message:@"Your internet connection seems to be lost."
                                                        delegate:nil
                                               cancelButtonTitle:@"OK"
                                               otherButtonTitles:nil];
        [alert show];

    }
} else {
    // Loop for mycompanyname mail domain and no authentication error
    NSLog(@"Loop 4 - mycompanyname domain email AND no Google login error.");

    // initialize app
}

}

The problem is that I cannot get the correct email address of the user who is trying to log in to be able to check accurately the email address and only initialize the app after.

I have done the checks with the errors and all using @gmail.com address to login, which explains why the codes are long.

Please help! Thanks in advance!

回答1:

I have encountered the exact same issue!

After hours and hours of looking into the GTMOAuth2 codes and logging everything and tracing the methods that were called along the way, I managed to get it to work!

What I did eventually to retrieve the email address was to hack into the GoogleOAuth class GTMOAuth2SignIn.m under method:

- (void)auth:(GTMOAuth2Authentication *)auth finishedWithFetcher:(GTMHTTPFetcher *)fetcher error:(NSError *)error 

This is because the authentication will show an error, which will result in the authenthication object not retrieving the values of the authenticated user. ie. not pulling the email address of the user.

Therefore I added a line to the method and now it shows as this:

- (void)auth:(GTMOAuth2Authentication *)auth finishedWithFetcher:(GTMHTTPFetcher*)fetcher error:(NSError *)error 
{
  self.pendingFetcher = nil;

#if !GTM_OAUTH2_SKIP_GOOGLE_SUPPORT

  if (error == nil && (self.shouldFetchGoogleUserEmail || self.shouldFetchGoogleUserProfile) && [self.authentication.serviceProvider isEqual:kGTMOAuth2ServiceProviderGoogle]) {
    // fetch the user's information from the Google server
    [self fetchGoogleUserInfo];
  } else {
    // we're not authorizing with Google, so we're done

    /**** CHANGED HERE TO CALL THE FETCH METHOD NO MATTER WHAT SO THAT THE EMAIL CAN BE SHOWN *****/
    [self fetchGoogleUserInfo];
     /**********************************************************************************************/
//[self finishSignInWithError:error]; // comment this out so that it will it will initiate a successful login
  }
#else
   [self finishSignInWithError:error];
#endif
}

After that, I used the same call

[_auth userEmail]

and was able to get the email address of the authenticated user.

It was a long, painful and hair pulling debugging session for me, so I hope this saved you some time and plenty of hair as well! :)



回答2:

try this . . . .

- (void)signInWithGoogle:(id)sender 
{
    GTMOAuth2Authentication * auth = [self authForGoogle];
    NSString * googleAuthURL = @"https://accounts.google.com/o/oauth2/auth";
    GTMOAuth2ViewControllerTouch * viewController = [[GTMOAuth2ViewControllerTouch alloc]
    initWithAuthentication:auth
    authorizationURL:[NSURL URLWithString:googleAuthURL]
    keychainItemName:@"GoogleKeychainName"

    completionHandler:^(GTMOAuth2ViewControllerTouch *viewController,
                      GTMOAuth2Authentication *auth, NSError *error) {

        if (error != nil)
        {
              //error  

        }
        else
        {
              googleAuth = auth;

              NSMutableDictionary * parameters = auth.parameters;

              NSString * email = [parameters objectForKey:@"email"];

       }
   }];

  }

}

-(GTMOAuth2Authentication *) authForGoogle
{

    NSString * googleTokenURL = token;
    NSString * googleClientID = client id;
    NSString * googleClientSecret = client secret;
    NSString * redirectURI = redirect uri;

    NSURL * tokenURL = [NSURL URLWithString:googleTokenURL];

    GTMOAuth2Authentication * auth ;

    auth = [GTMOAuth2Authentication authenticationWithServiceProvider:@"Google"
                                                             tokenURL:tokenURL
                                                          redirectURI:redirectURI
                                                             clientID:googleClientID
                                                         clientSecret:googleClientSecret  
   ];

    auth.scope = scope;

    return auth;
}