You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 18:58:28