403错误 - 这是一个错误。错误:不允许的用户代理。

54

我在IOS应用程序中尝试为Google日历API授权用户。我正在使用Google的OAuth2功能来验证用户身份。授权页面打开时出现403错误并显示以下描述:

此用户代理程序未被允许向Google发出OAuth授权请求,因为它被归类为嵌入式用户代理程序(也称为Web视图)。根据我们的政策,只有浏览器才可以向Google发出授权请求。我们提供了几个库和示例,供原生应用程序在浏览器中执行授权请求。

我遵循了这个链接中提到的相同过程:https://developers.google.com/google-apps/calendar/quickstart/ios

与其查看我的代码,不如查看这个链接:https://developers.google.com/google-apps/calendar/quickstart/ios,因为我将相同的东西复制粘贴到了我的应用程序中。

以下是我的clientId和keyChainItemName:

static NSString *const kKeychainItemName = @"Google Calendar API";
static NSString *const kClientID = @"954370342601-sgl8k0jrbqdeagea9v6vfu3tspte96ci.apps.googleusercontent.com";

展示你的源代码。 - Alexander Farber
你采用了什么方法? - Bhumit Mehta
@Subbhu,你解决了这个问题吗? - Alok
3
我在安卓中遇到了这个错误。通过为本地WebView设置“用户代理”解决了这个问题,即: String ua = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0"; webview.getSettings().setUserAgentString(ua); 你可以在这里找到更多关于IOS的信息:https://forums.xamarin.com/discussion/86415/google-auth-error-disallowed-useragent - Kalu Khan Luhar
2
该策略很糟糕,我们已经有了一种基于Webview的OAuth方法(多平台具有服务器端控制),适用于各种第三方应用。而现在我们要为Google应用程序提供特殊的浏览器流程?使用Webview允许我们通过服务器通信进行证书固定,同时使我们能够更好地控制从头部删除敏感信息,并且需要为同一个第三方应用程序提供多个帐户的登录便利(并非所有第三方API都可以强制提示登录,所以有时候必须使用Webview方法清除Cookie)。 - hmac
15个回答

36

在我的情况下,我正在使用本地WebView登录Google,我发现你应该向WebView提供用户代理的方法适用于我。尝试以下代码,我确信它会奏效。

将代码添加到application didFinishLaunchingWithOptions

Objective C

 NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:@"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36", @"UserAgent", nil];
 [[NSUserDefaults standardUserDefaults] registerDefaults:dictionary];

迅速的

UserDefaults.standard.register(defaults: ["UserAgent": "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36"])

2
只是为了澄清Objective C的解决方案。将此代码添加到:(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {} - itzo
仍然会出现相同的错误。还有其他人仍然面临相同的问题吗? - Rishi Raj
1
对我来说效果很好。您可以在此处找到新的UserAgent https://developers.whatismybrowser.com/useragents/explore/software_name/safari/?order_by=-software_version 并复制/粘贴字符串。 - Babac

17
<preference name="OverrideUserAgent" value="Mozilla/5.0 Google" />

我在我的 Cordova 项目中也遇到了这个问题。你可以尝试这个方法:只需将以下内容添加到你的 config.xml 中,这对我有用。


抱歉之前我的代码没有正确显示,现在我已经进行了更正。你可以尝试一下这个代码:<preference name="OverrideUserAgent" value"Mozilla/5.0 Google" /> - Hardeep Singh
2
我在Android上遇到了同样的问题,你能建议我如何解决吗? - NareshRavva
请问您使用哪个平台来创建Android应用程序,例如Cordova、Ionic或在Android Studio中使用本机Android应用程序? - Hardeep Singh
Android Studio中的本地Android应用程序 - NareshRavva
1
对于使用电容器的人,请在 capacitor.config.json 中更新以下内容:"overrideUserAgent": "Mozilla/5.0 Google" - Bart Boersma

16
简短回答是,Google已经更新了其OAuth流程的安全限制。他们不再允许原生Web视图启动OAuth流程,而是鼓励用户使用操作系统浏览器进行操作。在您的情况下,您可能需要等待Google日历SDK更新其代码以遵守新推荐的流程。更多信息请参见Google博客
编辑:我尝试创建一个跨平台插件,将本地的Google登录SDK包装成Xamarin表单应用程序中可用的形式。有关更多信息,请参见此处

非常感谢@Rhishkeshj,但这并没有解决我的问题。我想知道是否有其他可用的替代方案... 我仍在寻找答案。 - Subbu
问题也被记录在驱动器上 https://code.google.com/a/google.com/p/apps-api-issues/issues/detail?id=4919 - Linda Lawton - DaImTo
@Subbu 很不幸,目前还没有简单的解决方案。我所做的是使用本地的 Google 登录 SDK,并将其分别集成到 iOS 和 Droid 项目中。看起来效果还不错,尽管从 PCL 中的使用目前非常有限。我正在尝试将这个设置开发成一个独立的插件。让我们拭目以待。 - Rhishikeshj
令人难以置信的是,这个问题也会出现在 Android 4.x 的原生浏览器中,这是在 Chrome 垄断和可更新的 Webview 时代之前的。 - andreszs

12

我遇到了同样的问题。通过将以下属性设置为webview对象而解决:

webview.getSettings().setUserAgentString("Chrome/56.0.0.0 Mobile");

希望这能有所帮助。

8
如前面的回答所提到的,SFSafariViewController是一个不错的选择,但对于仍在使用WKWebView进行OAuth授权的人来说,有一个简单的解决方法。
只需将customUserAgent更改为来自列表中的任意值或将其设置为任意值。之后,disallowed_useragent错误就会消失。
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration];
// Check for selector availability, as it is available only on iOS 9+
if ([webView respondsToSelector:@selector(setCustomUserAgent:)]) {
    webView.customUserAgent = @"MyCustomUserAgent";
}

如果你想要在UIWebView中更改User-Agent,你可以参考这个答案

但是需要注意的是,一些后端代码可能会依赖于User-Agent头部的值。


对我来说完美无缺 :) - Valentin

3
谷歌决定不再允许嵌入式浏览器处理oAuth认证。在iOS上使用SFSafariViewController是最好的方法。以下是使用CloudRail SDK解决此问题的方法:
Objective-C代码如下:
@implementation AppDelegate

  // This method will receive the redirect URI after the authentication process was
  // successfull
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {

  // Here we pass the response to the SDK which will automatically
  // complete the authentication process.
  [[NSNotificationCenter defaultCenter] postNotificationName:@"kCloseSafariViewControllerNotification" object:url];

  return YES;
}

@end

和Swift:

// This method will receive the redirect URI after the authentication process was
// successfull
func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject) -> Bool {

    if (sourceApplication == "com.apple.SafariViewService") {
        // Here we pass the response to the SDK which will automatically
        // complete the authentication process.
        NSNotificationCenter.defaultCenter().postNotificationName("kCloseSafariViewControllerNotification", object: url)
        return true
    }
    return true
}

您可以在此处找到涵盖此问题的完整博客文章:解决Google服务的“disallowed_useragent”


需要更多细节,请@Tmm。 - Shourob Datta

3

默认情况下,如果您没有任何谷歌应用程序,当我们使用以下方法启动登录时,谷歌SDK会在UIWebView中打开登录。

        [[GIDSignIn sharedInstance] signIn];

在此之前,我刚刚添加了一行代码,如下所示。

        [[GIDSignIn sharedInstance] setAllowsSignInWithWebView:NO];

现在,谷歌不允许使用UIWebView弹出窗口。相反,它在Safari浏览器中打开。现在一切都按照原来的方式正常工作。


在我的情况下,这解决了问题!非常感谢你! - Tavados
谢谢你,你救了我。 - Sommm

2

GTMAppAuth也是Google提供的实际解决方案。谢谢,Carolyn。 - Chandan

2

最近Google OAuth政策的变化后,这个问题有一个解决方法。

在集成Google登录并启用Google日历API后,我能够使用Google日历API获取和添加日历事件。我们只需要为GTLServiceCalendar设置授权器,该授权器是在Google登录后获得的。

service.authorizer = user.authentication.fetcherAuthorizer()

以下是Google GIDSignIn的代码片段,接着便是获取日历事件。

import GoogleAPIClient
import GTMOAuth2
import UIKit
import GoogleSignIn

class ViewController: UIViewController, GIDSignInUIDelegate, GIDSignInDelegate {

  private let kApiKey = "AIzaXXXXXXXXXXXXXXXXXXXXXXX"

  // If modifying these scopes, delete your previously saved credentials by
  // resetting the iOS simulator or uninstall the app.
  private let scopes = [kGTLAuthScopeCalendar]
  private let service = GTLServiceCalendar()

  override func viewDidLoad() {
      super.viewDidLoad()

      service.apiKey = kApiKey

      GIDSignIn.sharedInstance().uiDelegate = self
      GIDSignIn.sharedInstance().scopes = scopes
      GIDSignIn.sharedInstance().signIn()
      GIDSignIn.sharedInstance().delegate = self
  }


  func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {

      if user != nil {
           print("\(user)")
           service.authorizer = user.authentication.fetcherAuthorizer()
           fetchEvents()
      }
  }

 // Construct a query and get a list of upcoming events from the user calendar
   func fetchEvents() {

        let query = GTLQueryCalendar.queryForEventsList(withCalendarId: "primary")
        query?.maxResults = 20
        query?.singleEvents = true
        query?.orderBy = kGTLCalendarOrderByStartTime

        service.executeQuery(query!, delegate: self, didFinish: #selector(ViewController.displayResultWithTicket(ticket:finishedWithObject:error:)))
   }

// Display the start dates and event summaries in the UITextView
    func displayResultWithTicket(
         ticket: GTLServiceTicket,
        finishedWithObject response : GTLCalendarEvents,
        error : NSError?) {

        if let error = error {
            showAlert(title: "Error", message: error.localizedDescription)
            return
        }

        var eventString = ""

        if let events = response.items(), !events.isEmpty {
            for event in events as! [GTLCalendarEvent] {
                print(event)
             }
        } else
                print("No upcoming events found.")
        }
    }

    }

这是我的凭据部分在Google Dev控制台中的显示方式。 enter image description here

你好,@Jen Jose,能帮我一下吗?我需要创建并保存事件。 - Dilip Tiwari
@DilipTiwari,你卡在哪里了?即使 Dipen 的答案可行,但我个人更喜欢不要干涉 Safari 首选项,最好使用错误中提到的 Google 授权器。 - Jen Jose
我已经按照这个链接 https://developers.google.com/google-apps/calendar/quickstart/ios 成功显示了按钮,并进一步进行了与谷歌的登录过程。当我在Web浏览器中添加事件时,我能够在ViewController的TextView中显示相同的事件,但我想知道如何在iOS应用程序Swift中创建事件并保存。@Jen Jose - Dilip Tiwari
如果您愿意,我可以通过Skype或个人聊天进行指导。 - Dilip Tiwari
我已经成功地集成了Google登录并启用了Google日历API,但是如何使用Google日历API来获取和添加日历事件呢?需要帮助。 - Dilip Tiwari
显示剩余4条评论

1

这对我很有效

mWebView.getSettings().setUserAgentString("Mozilla/5.0 (Linux; Android 4.1.1; Galaxy Nexus Build/JRO03C) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19");

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接