Golang中实现Google登录

很多业务场景中需要使用三方登录,微信和支付宝登录很常用,那么使用谷歌登陆时需要做些什么?

首选先来介绍一下使用OAuth进行认证和授权的流程大致如下:

  1. 用户打开客户端以后,客户端要求用户给予授权。
  2. 用户同意给予客户端授权。
  3. 客户端使用上一步获得的授权,向认证服务器申请令牌。
  4. 认证服务器对客户端进行认证以后,确认无误,同意发放令牌。
  5. 客户端使用令牌,向资源服务器申请获取资源。
  6. 资源服务器确认令牌无误,同意向客户端开放资源

在进入开发之前我们得先需要申请一个谷歌应用,其申请流程如下:

  1. 去Google Cloud Platform,创建一个项目
  2. 凭据,创建凭据,选择OAuth客户端ID
  3. 选择应用类型为”网页应用”,输入对应自身项目的JavaScript来源和已获授权的重定向URI(登陆后的回调地址)
  4. 记录下客户端ID和客户端密钥

大致如下图所示:

 

 

一切都准备就绪,接下来开始进入功能实现

首先安装oauth2.0的包:

go get golang.org/x/oauth2

然后开始进行编码:

var (
    googleOauthConf *oauth2.Config
)

func init() {
    googleOauthConf = &oauth2.Config{
        RedirectURL:  "你的回调地址",
        ClientID:     "你的客户端ID",
        ClientSecret: "你的客户端密钥",
        Scopes: []string{
            "https://www.googleapis.com/auth/userinfo.email",//用来获取邮箱的
            "https://www.googleapis.com/auth/userinfo.profile",//用来获取用户基础信息的
        },
        Endpoint: google.Endpoint,
    }
}

func (s service) GooGleLogin(ctx *core.Context, param dto.GooGleLoginParam) (result dto.GooGleLoginResult, err error) {
    //根据code换取token
  token, err := googleOauthConf.Exchange(context.Background(), param.Code)
  if err != nil {
    log.Errorf(ctx, "Failed to get user token:", err)
    return
  }
//根据token获取用户信息
    client := googleOauthConf.Client(context.Background(), token)
    userInfoURL := "https://www.googleapis.com/oauth2/v3/userinfo"
    res, err := client.Get(userInfoURL)
    if err != nil {
        log.Errorf(ctx, "Failed to get user info:", err.Error())
        return
    }
    defer res.Body.Close()
    var userInfo struct {
        GoogleUserId string `json:"sub"`
        Email        string `json:"email"`
        UserName     string `json:"name"`
        Picture      string `json:"picture"`
        Locale       string `json:"locale"`
    }
    err = json.NewDecoder(res.Body).Decode(&userInfo)
    if err != nil {
        log.Errorf(ctx, "Failed to decode user info:", err.Error())
        return
    }

    //检测用户是否存在
    data := models.User{}
    err = core.DB(ctx).Where(&models.User{
        GoogleUserId: userInfo.GoogleUserId,
        DeletedAt:    0,
        Status:       1,
    }).First(&data).Error

    tokenStr, errs := core.CreateToken(userInfo.GoogleUserId)
    if errs != nil {
        log.Errorf(ctx, "Failed to generate token:", errs.Error())
        return
    }

    if err != nil {
        //如果是记录找不到的话就新增用户
        if errors.Is(err, gorm.ErrRecordNotFound) {
            one := models.User{
                GoogleUserId: userInfo.GoogleUserId,
                UserName:     userInfo.UserName,
                Email:        userInfo.Email,
                AvatarUrl:    userInfo.Picture,
                Locale:       userInfo.Locale,
            }
            err = core.DB(ctx).Save(&one).Error
            if err != nil {
                log.Errorf(ctx, "Failed to save user info:", err.Error())
            }
            result = dto.GooGleLoginResult{
                ID:           one.Id,
                GoogleUserId: one.GoogleUserId,
                UserName:     one.UserName,
                Email:        one.Email,
                AvatarUrl:    one.AvatarUrl,
                Locale:       one.Locale,
                Token:        tokenStr,
            }
            return
        }
        return
    }
    //已存在,返回用户信息
    result = dto.GooGleLoginResult{
        ID:           data.Id,
        GoogleUserId: data.GoogleUserId,
        UserName:     data.UserName,
        Email:        data.Email,
        AvatarUrl:    data.AvatarUrl,
        Locale:       data.Locale,
        Token:        tokenStr,
    }
    return
}

以上即可实现谷歌登陆的功能~

需要注意的是我们这里使用的逻辑为:前端发起登录拉起跳转,获取code,像后端传输code获取用户信息,所以拉起谷歌登录的链接为:

https://accounts.google.com/o/oauth2/v2/auth?client_id=你的客户端ID&redirect_uri=你的回调地址&response_type=code&scope=https://www.googleapis.com/auth/userinfo.email+https://www.googleapis.com/auth/userinfo.profile+openid

这里的scope是两个链接,一个是邮箱获取,一个是用户基础信息获取,也可以使用email+profile+openid,效果是一样的,这里按需获取即可

 

posted @ 2024-06-14 10:50  你的男孩  阅读(297)  评论(0编辑  收藏  举报