Golang中实现Google登录
很多业务场景中需要使用三方登录,微信和支付宝登录很常用,那么使用谷歌登陆时需要做些什么?
首选先来介绍一下使用OAuth进行认证和授权的流程大致如下:
- 用户打开客户端以后,客户端要求用户给予授权。
- 用户同意给予客户端授权。
- 客户端使用上一步获得的授权,向认证服务器申请令牌。
- 认证服务器对客户端进行认证以后,确认无误,同意发放令牌。
- 客户端使用令牌,向资源服务器申请获取资源。
- 资源服务器确认令牌无误,同意向客户端开放资源
在进入开发之前我们得先需要申请一个谷歌应用,其申请流程如下:
- 去Google Cloud Platform,创建一个项目
- 凭据,创建凭据,选择OAuth客户端ID
- 选择应用类型为”网页应用”,输入对应自身项目的JavaScript来源和已获授权的重定向URI(登陆后的回调地址)
- 记录下客户端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,效果是一样的,这里按需获取即可