如何在使用Google OAuth 2.0时阻止显示访问代码的额外视图

时间:2011-09-26 16:05:17

标签: ios oauth-2.0

我关注http://googlemac.blogspot.com/2011/05/ios-and-mac-sign-in-controllers.html以允许用户使用Google登录iPhone应用。点击“允许访问”按钮后,我会看到一个额外的屏幕,“请复制此代码,切换到您的应用程序并将其粘贴到那里:(文本框中的代码)。”

这就是我所拥有的:

- (IBAction)googleLoginTapped:(UIButton *)sender
{
    [self loginToGoogle];
}

- (void)loginToGoogle 
{

    // For Google APIs, the scope strings are available
    // in the service constant header files.
    NSString *scope =@"https://www.googleapis.com/auth/userinfo.profile";

    // Typically, applications will hardcode the client ID and client secret
    // strings into the source code; they should not be user-editable or visible.

    // But for this sample code, they are editable.
    NSString *clientID = @"my clientID";
    NSString *clientSecret = @"my clientSecret";


    // Display the autentication view.
    SEL finishedSel = @selector(viewController:finishedWithAuth:error:);

    GTMOAuth2ViewControllerTouch *viewController;

    viewController = [GTMOAuth2ViewControllerTouch controllerWithScope:scope
                                                              clientID:clientID
                                                          clientSecret:clientSecret
                                                      keychainItemName:nil
                                                              delegate:self
                                                      finishedSelector:finishedSel];

    // For this sample, we'll force English as the display language.
    NSDictionary *params = [NSDictionary dictionaryWithObject:@"en"
                                                       forKey:@"hl"];

    viewController.signIn.additionalAuthorizationParameters = params;

    // Optional: display some html briefly before the sign-in page loads
    NSString *html = @"<html><body bgcolor=silver><div align=center>Loading sign-in page...</div></body></html>";
    viewController.initialHTMLString = html;

    viewController.signIn.shouldFetchGoogleUserProfile = YES;

    [self presentModalViewController:viewController animated:YES];
}

- (void)viewController:(GTMOAuth2ViewControllerTouch *)viewController finishedWithAuth:(GTMOAuth2Authentication *)auth error:(NSError *)error
{
    if (error != nil) 
    {
        // Authentication failed (perhaps the user denied 

请查看此链接是好https://developers.google.com/accounts/docs/OAuth2InstalledApp

8 个答案:

答案 0 :(得分:9)

我试过这种方法,并且工作正常,把它放在你的webViewDidFinishLoad方法中:

if ([webView.request.URL.absoluteString rangeOfString:@"https://accounts.google.com/o/oauth2/approval?"].location != NSNotFound) {
    webView.hidden=YES;
}

答案 1 :(得分:6)

我找到了答案。最初我使用客户端ID来安装应用程序。这没有提供设置重定向URI的选项。它提供了一个默认的重定向URI urn:ietf:wg:oauth:2.0:oob http://localhost所以当我使用此代码发送身份验证请求时:

viewController = [GTMOAuth2ViewControllerTouch controllerWithScope:scope
                                                              clientID:clientID
                                                          clientSecret:clientSecret
                                                      keychainItemName:nil
                                                              delegate:self
                                                      finishedSelector:finishedSel];

它返回了一个成功代码,然后用于授权本机应用程序。有关返回的代码或令牌的更多信息,请提供here

为解决我的问题,我继续使用客户端ID进行Web应用程序。这允许我显式设置重定向URI,并允许我在这里将response_type设置为令牌而不是代码:

https://accounts.google.com/o/oauth2/auth?
  client_id=21302922996.apps.googleusercontent.com&
  redirect_uri=https://www.example.com/back&
  scope=https://www.google.com/m8/feeds/&
  response_type=**token**

因此,当我通过身份验证并从服务器返回redirect_uri时,会附带一个“access_tocken”作为查询字符串,如下所示:

https://www.example.com/back?access_token=returned_access_tocken

现在您可以使用正则表达式代码:

-(void)checkForAccessToken:(NSString *)urlString {
    NSError *error;
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"access_token=(.*)&" options:0 error:&error];
    if (regex != nil) 
    {
        NSTextCheckingResult *firstMatch = [regex firstMatchInString:urlString options:0 range:NSMakeRange(0, [urlString length])];
        if (firstMatch) 
        {
            NSRange accessTokenRange = [firstMatch rangeAtIndex:1];
            NSString *accessToken = [urlString substringWithRange:accessTokenRange];
            accessToken = [accessToken stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
            [_delegate accessTokenFoundGoogle:accessToken];
            accessTokenFound = YES;
        }
    }
}

选择access_code并将其用于您的授权请求:

"https://www.googleapis.com/oauth2/v1/userinfo?oauth_token=put_your_accesstoken_here" to send a request for authorization

然后你可以发送你的请求,并在这种情况下以JSON格式返回用户的个人资料信息。您可以参考此question and answer使用Facebook的图形API来登录用户。然后,只需使用我在此处提供的建议和请求网址修改代码即可使用新的Google OAuth 2.0。只是在转换Facebook代码时为您加速的建议,创建一个新的init方法,如下所示:

- (id)initWithDelegate:(id<GoogleLoginDialogDelegate>)delegate;

- (id)initWithDelegate:(id<GoogleLoginDialogDelegate>)delegate 
{
    if ((self = [super initWithNibName:@"GoogleLoginDialog" bundle:[NSBundle mainBundle]])) {
        self.delegate = delegate;
    }
    return self;    
}

这样您就可以轻松使用Google登录对话框中的委托方法。如果您仔细关注Facebook示例,那么您应该让Google登录OAuth工作得非常好!

答案 2 :(得分:5)

事实证明这非常简单。在登录回调中,只需从父视图控制器中解除并删除viewController

- (void)viewController:(UIViewController *)viewController
      finishedWithAuth:(GTMOAuth2Authentication *)auth
                 error:(NSError *)error
{
    if (error == nil) {
        // Get rid of the login view.
        // self.parentViewController was saved somewhere else and is the parent
        // view controller of the view controller that shows the google login view.
        [self.parentViewController dismissViewControllerAnimated:NO completion:nil];
        [viewController removeFromParentViewController];

        // Tell the delegate that the user successfully logged in ...
    } else {
        // Error handling code ...
    }
}

答案 3 :(得分:1)

我通过将视图控制器嵌套在UINavigationController内来修复此问题。不知道为什么会这样做,但确实如此。

所以而不是

[self presentModalViewController:viewController animated:YES];

...使用

UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
[self presentModalViewController:navigationController animated:YES];

答案 4 :(得分:0)

使用gtm-oauth2登录Google服务时,请确保{API}访问权限部分中的Google API Console项目注册显示为已安装的应用程序颁发了客户端ID。这在gtm-oauth2 documentation中有所描述。

答案 5 :(得分:0)

创建客户端ID时,选择Web应用程序而不是已安装的应用程序,这将解决您的问题。

快乐编码:)

答案 6 :(得分:0)

我试过这个技巧,它就可以了......

GTMOAuth2ViewControllerTouch.h 中使用以下方法替换webview shouldStartLoadWithRequest 。它不会显示身份验证代码页。

*- (BOOL)webView:(UIWebView *)webView
  shouldStartLoadWithRequest:(NSURLRequest *)request
              navigationType:(UIWebViewNavigationType)navigationType {
    if (!hasDoneFinalRedirect_)
    {
        hasDoneFinalRedirect_ = [signIn_ requestRedirectedToRequest:request];

        if ([request.URL.absoluteString rangeOfString:@"https://accounts.google.com/o/oauth2/approval?"].location != NSNotFound)
        {
            self.redirectView.frame=[UIScreen mainScreen].bounds;
            //webView.frame=[UIScreen mainScreen].bounds;
            [self.activityView startAnimating];
            [webView addSubview:self.redirectView];

            return YES;
        }
        else if(hasDoneFinalRedirect_) {
            // signIn has told the view to close
            return NO;
        }
    }

    return YES;
}*

在此我通过检查此审批网址https://accounts.google.com/o/oauth2/approval?

将我自己的自定义视图(redirectView)添加到此身份验证页面

并且您还应该在GTMOAuth2ViewControllerTouch的xib中添加activityView,以在重定向回应用程序时显示加载器。

答案 7 :(得分:0)

经过至少20个小时的配置后,我终于开始运行了。我之前也将我的swift文件导入了我的GTMOAuth2ViewControllerTouch.m文件。不确定是否影响了它,但我补充道:

    #import "myBundleId-Swift.h"

然后,在viewController.swift文件中,我需要添加最后两行:

 // Handle completion of the authorization process, and updates the Drive service
// with the new credentials.
func viewController(viewController: GTMOAuth2ViewControllerTouch , finishedWithAuth authResult: GTMOAuth2Authentication, error:NSError? ) {
    if let error = error
    {
        self.showAlert("Authentication Error", message:error.localizedDescription)
        self.driveService.authorizer = nil
    } else {
        print("Authentication success")
        self.driveService.authorizer = authResult
//This where we need to get rid of the copy the code screen:
        self.parentViewController?.dismissViewControllerAnimated(false, completion:nil)
        viewController.removeFromParentViewController()
    }
}

摆脱了这个代码屏幕的复制。