即使应用已通过身份验证,Google通讯录API也会返回401

时间:2017-07-29 17:31:29

标签: android authentication oauth google-signin

所以,我正在开发应用程序的Android端,我需要让用户与他/她的Google联系人共享图像。为此,我显然需要用户的授权才能访问他或她的Google联系人。我们实现这一目标的方式如下:

  • 在Android上,我使用的是Google标准的Auth Sign in API(使用OAuth 2.0)
  • 在Backend上,我使用Contacts API检索联系人以将联系人发送到设备(我知道您可能想知道为什么我没有直接在移动设备上使用联系人API,但原始的API安排有由其他人撰写

所以,我只是按照Google的OAuth安排规定的流程进行操作。首先,我要求API授权授权代码。接下来,我发送此代码以获取访问令牌,然后最终将此访问令牌发送到我的服务器以通过Contacts API进行调用。

我向用户请求授权时获得的请求访问屏幕是:

enter image description here

最后,Contacts API发送了以下请求(示例请求来自许多):

  

https://www.google.com/m8/feeds/groups/default/full?alt=json&access_token=ya29.GluXBJvdEgHD4XrieSgukvfvE0-XlNSwxDF8aaLMLHaXxE3Qd6G2Gy2h18WUOvOg--U0ffobyEzJiXIWtW2sRtdND8B6zcCVrvQm0kfOSBAJcdA4-9i6JZ7CH8y1&v=3.0

但回复的回复是401.为什么它不是未经身份验证的,我不明白。我调试了几个小时,检查OAuth进程是否完全正常。

还有一件事,我使用以下范围登录Google:

GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                .requestServerAuthCode(CLIENT_ID, true)
                .requestScopes(new Scope(Scopes.DRIVE_APPFOLDER), new Scope(Scopes.PROFILE))
                .requestEmail()
                .requestProfile()
                .requestIdToken(CLIENT_ID)
                .build();

有人可能会遇到什么问题吗?

修改

我提供了一些详细信息,证明API密钥,OAuth ID等的设置已经正确完成。

  • 首先,我正在使用Web应用程序OAuth客户端ID来请求Google提供的授权代码,如官方指南here所示。
  • 我的应用程序的SHA-1调试指纹已添加到我的项目中,因此Google并没有抱怨这一点。
  • 我在接收访问令牌后使用的重定向网址也已添加到我的Web OAuth客户端。
  • 我正在为我的项目启用我正在使用服务器端的Contacts API。

1 个答案:

答案 0 :(得分:1)

正如我所怀疑的那样,Scope证明是一个问题。

首先,让我告诉你,我一般都喜欢谷歌的精彩文档和API,但有些情况下,看似简单的细节被视为理所当然,开发人员感觉自己正在自己调试它们。我觉得,这是其中一个问题。

因此,任何启动Google登录集成的人都会查看官方文档和指南, 在文档中提及和使用范围,但是这样:

GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                .requestServerAuthCode(CLIENT_ID, true)
                .requestScopes(new Scope(Scopes.DRIVE_APPFOLDER), new Scope(Scopes.PROFILE), new Scope(Scopes.EMAIL))
                .requestEmail()
                .requestProfile()
                .requestIdToken(CLIENT_ID)
                .build();

这是来自示例代码段。当然,开发人员从示例代码段中复制并进一步扩展它。那么,作为开发人员,我将如何扩展呢?

嗯,首先,我可以清楚地传递更多的范围吗?

这是对的,我做了那件事,但仍然遇到了这个问题。毕竟,我所要做的只是添加适当的范围。怎么会有人被这样打击?让我告诉你Scopes类是什么样的:

public final class Scopes {
    public static final java.lang.String PROFILE = "profile";
    public static final java.lang.String EMAIL = "email";
    public static final java.lang.String PLUS_LOGIN = "https://www.googleapis.com/auth/plus.login";
    public static final java.lang.String PLUS_ME = "https://www.googleapis.com/auth/plus.me";
    public static final java.lang.String GAMES = "https://www.googleapis.com/auth/games";
    public static final java.lang.String CLOUD_SAVE = "https://www.googleapis.com/auth/datastoremobile";
    public static final java.lang.String APP_STATE = "https://www.googleapis.com/auth/appstate";
    public static final java.lang.String DRIVE_FILE = "https://www.googleapis.com/auth/drive.file";
    public static final java.lang.String DRIVE_APPFOLDER = "https://www.googleapis.com/auth/drive.appdata";
    public static final java.lang.String FITNESS_ACTIVITY_READ = "https://www.googleapis.com/auth/fitness.activity.read";
    public static final java.lang.String FITNESS_ACTIVITY_READ_WRITE = "https://www.googleapis.com/auth/fitness.activity.write";
    public static final java.lang.String FITNESS_LOCATION_READ = "https://www.googleapis.com/auth/fitness.location.read";
    public static final java.lang.String FITNESS_LOCATION_READ_WRITE = "https://www.googleapis.com/auth/fitness.location.write";
    public static final java.lang.String FITNESS_BODY_READ = "https://www.googleapis.com/auth/fitness.body.read";
    public static final java.lang.String FITNESS_BODY_READ_WRITE = "https://www.googleapis.com/auth/fitness.body.write";
    public static final java.lang.String FITNESS_NUTRITION_READ = "https://www.googleapis.com/auth/fitness.nutrition.read";
    public static final java.lang.String FITNESS_NUTRITION_READ_WRITE = "https://www.googleapis.com/auth/fitness.nutrition.write";

    private Scopes() { /* compiled code */ }
}

所以,开发人员认为,

  

“这些都是支持的范围,我所要做的就是参考a   带有Scopes.SCOPE_NAME

有效范围

但是猜猜怎么着?范围内的故事还有更多内容!

原则上,您可以使用您要定位的Google API的端点创建自己的范围。就我而言,它是我使用的Contacts API,所以新代码看起来像这样:

GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                .requestServerAuthCode(CLIENT_ID, true)
                .requestScopes(new Scope(Scopes.DRIVE_APPFOLDER), new Scope(Scopes.PROFILE), new Scope(Scopes.EMAIL), new Scope("https://www.google.com/m8/feeds/"))
                .requestEmail()
                .requestProfile()
                .requestIdToken(CLIENT_ID)
                .build();

您是否注意到了额外的范围:

new Scope("https://www.google.com/m8/feeds/")
是的,就是这样。这就是答案。

那么,究竟是什么刺激了我的蜘蛛侠意识?

您会看到,在Google提供的上述权限页面中,它没有提及有关“联系人”的任何内容。但是,我想访问联系人。那是一个明显的红旗!

添加其他范围后,它显示“想要管理您的联系人”。(您的aha!时刻)

最后一件事 -

我如何知道范围的URI?

嗯,这很简单。您最有可能在目标相应API的doc /指南中找到它。另外,请在提供的样本中注意。因此,下次您遇到身份验证时,请先查找正确的范围。