如何实现GitHub社交登录以获取用户私有邮箱用于认证
实现GitHub私有邮箱获取的社交登录方案
一、核心前提:申请正确的OAuth权限
GitHub OAuth默认仅返回用户公开信息,要获取私有邮箱,必须在引导用户跳转到GitHub授权页的URL中添加scope=user:email参数。例如:
原授权URL:https://github.com/login/oauth/authorize?client_id=你的ClientID
修改后:https://github.com/login/oauth/authorize?client_id=你的ClientID&scope=user:email
没有这个权限的话,调用/user/emails接口会返回权限不足的错误。
二、代码修改实现私有邮箱获取
现有代码仅调用了/user接口获取公开信息,我们需要新增逻辑调用/user/emails接口拿到所有邮箱(含私有),并筛选出可用的认证邮箱。
1. 新增邮箱数据结构体
添加用于解析邮箱接口返回结果的结构体:
type GithubEmail struct { Email string `json:"email"` Primary bool `json:"primary"` Verified bool `json:"verified"` }
2. 新增获取邮箱列表的函数
添加专门调用/user/emails接口的函数:
func GetGithubEmails(accessToken string) []GithubEmail { req, reqerr := http.NewRequest("GET", "https://api.github.com/user/emails", nil) if reqerr != nil { log.Panic("Emails API Request creation failed") } authorizationHeaderValue := fmt.Sprintf("token %s", accessToken) req.Header.Set("Authorization", authorizationHeaderValue) req.Header.Set("Accept", "application/vnd.github.v3+json") // 指定API版本,避免兼容问题 resp, resperr := http.DefaultClient.Do(req) if resperr != nil { log.Panic("Emails request failed") } defer resp.Body.Close() // 关闭响应体,避免资源泄漏 respbody, err := ioutil.ReadAll(resp.Body) if err != nil { log.Panic("Failed to read emails response body") } var emails []GithubEmail json.Unmarshal(respbody, &emails) return emails }
3. 整合登录流程逻辑
在获取access_token后,先拿用户基本信息,若公开邮箱为空,则从私有邮箱列表中筛选主邮箱(已验证)作为认证邮箱:
// 示例登录处理逻辑 func HandleGithubLogin(code string) (*GithubUser, error) { accessToken := GetGithubAccessToken(code) userData := GetGithubData(accessToken) var user GithubUser err := json.Unmarshal(userData, &user) if err != nil { return nil, err } // 公开邮箱为空时,从私有邮箱列表获取 if user.Email == "" { emails := GetGithubEmails(accessToken) for _, email := range emails { // 优先选择已验证的主邮箱 if email.Primary && email.Verified { user.Email = email.Email break } } } return &user, nil }
三、注意事项
- 必须确保授权URL包含
scope=user:email,否则无法获取私有邮箱权限。 - 筛选邮箱时优先选择
primary和verified双为true的条目,这是用户确认的主邮箱,适合作为认证标识。 - 代码中建议替换
log.Panic为错误返回,让上层逻辑处理异常,提升程序健壮性。
内容的提问来源于stack exchange,提问作者Egon
相关产品推荐
相关产品推荐

