尽管用户已经授权 user:email 权限,但 Github 用户电子邮件为空。

64
我正在遵循Github的OAuth流程,并获得一个访问令牌,使我可以访问用户的电子邮件范围。当我使用https://github.com/login/oauth/access_token端点交换代码以获取访问令牌时,我会收到以下响应:
{
  access_token: '83f42..xxx’,
  token_type: 'bearer',
  scope: 'user:email' 
}

看起来很棒。因此,我使用令牌发出此请求,以获取我的用户数据:

Accept-Language: en-us
Accept: application/json
Authorization: token 83f42..xxx
Accept-Encoding: gzip, deflate

GET https://api.github.com/user

我得到了用户对象的响应,但电子邮件属性为空。还有其他人遇到这个问题吗?
3个回答

100

我已经找出为什么会发生这种情况以及如何解决。根据 文档:

注意:返回的电子邮件是用户的公开可见电子邮件地址(如果用户在其个人资料中未指定公共电子邮件地址,则为 null)。

在您的 GitHub 资料设置中,位于公开电子邮件下的某些用户(包括我自己)将该选项设置为“不显示我的电子邮件地址”。对 /user 的调用仅返回公开电子邮件地址,因此如果用户不想显示该信息,则 API 将尊重用户的选择。

enter image description here

要获取用户的电子邮件地址,无论其是否公开,请使用调用/user/emails。您将像处理 /user 请求一样使用访问令牌:

Accept-Language: en-us
Accept: application/json
Authorization: token 83f42..xxx
Accept-Encoding: gzip, deflate

GET https://api.github.com/user/emails

这个调用给了我以下的 JSON 响应:

[
  {
    "email": "user@example.com",
    "primary": true,
    "verified": true
  }
]

6
使用 passport-github 和 node.js,解决方案是将 scope: [ 'user:email' ] 传递给 GitHubStrategy 构造函数。请注意,您将获得用户电子邮件的数组,如果您想要筛选出 primary:true 等内容,请进行过滤。 - Anton Drukh
@AntonDrukh,您能详细说明一下吗?passport-github的咒语是什么? - Fergie
1
@Fergie 请看下面我的答案,评论写不下了。 - Anton Drukh
@AntonDrukh 干杯! - Fergie
@IvanKuckir 我不这么认为。 /user 端点“提供有关拥有 GitHub 帐户的某个人的公开可用信息。” 您需要进行另一个 API 调用以检索私人电子邮件。 - Alexander
显示剩余4条评论

11

无法在评论中添加,因此回答关于node.js passport-github的情况:

var GitHubStrategy = require('passport-github').Strategy;

passport.use('github-login', new GitHubStrategy({
  clientID: config.clientId,
  clientSecret:  config.secret,
  callbackURL: config.host + config.callback,
  passReqToCallback: true, // req object on auth is passed as first arg
  scope: [ 'user:email' ], // fetches non-public emails as well
},
  function (req, accessToken, refreshToken, profile, done) {
    // find user by profile and update it
    // or create the user object given the req, tokens and profile objs
    // don't forget to call `done(null, user)` once done
}
));

2
这个问题的重点在于,在某些情况下,仅请求“user:email”范围是不够的 - 对于某些用户,您仍将获得空电子邮件。 @Alexander的答案涵盖了这种用例,并可以视为对您的答案的补充,在返回的配置文件的电子邮件为空的情况下。 - fisch2
对于通行证,可以在“authorize”调用中指定“scope”。这似乎适用于Google和Facebook,但不适用于GitHub。这种方法适用于GitHub。非常感谢。 - Umar Farooq Khawaja

1
您需要使用访问令牌向https://api.github.com/user/emails发起额外的请求。
完整的身份验证流程如下:
  1. 要获取“Code”,首先将用户重定向到 https://github.com/login/oauth/authorize?client_id={CLIENTID}&redirect_uri={REDIRECT_URL}&scope=read:user,user:email

  2. 然后,使用您收到的“Code”进行POST请求以获取访问令牌,如下所示: https://github.com/login/oauth/access_token?client_id={clientID}&client_secret={clientSecret}&code={code}

  3. 现在,当您收到访问令牌时,首先向/user端点发出请求,然后再向/user/emails端点发出请求。确保在头部中传递访问令牌,并使用参数Authorization: "token {accessToken}"

要获取基本用户数据,请向此URL发出GET请求: https://api.github.com/user 然后,要获取用户电子邮件,请向https://api.github.com/user/emails发出GET请求。
您可能会在结果中获得多个电子邮件。结果将类似于此:
[
  {
    email: 'johndoe100@gmail.com',
    primary: true,
    verified: true,
    visibility: 'public'
  },
  {
    email: 'johndoe111@domain.com',
    primary: false,
    verified: true,
    visibility: null
  }
]

您可以选择将primary参数设置为true的那个。

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