添加google第三方登录
This commit is contained in:
parent
97ce265dab
commit
4ea300f522
|
|
@ -31,7 +31,8 @@ type User struct {
|
||||||
type ThirdPartyUserInfo struct {
|
type ThirdPartyUserInfo struct {
|
||||||
gorm.Model
|
gorm.Model
|
||||||
UserID int `json:"user_id"` // 用户ID,本系统的用户id
|
UserID int `json:"user_id"` // 用户ID,本系统的用户id
|
||||||
ThirdPartyID int `json:"third_party_id"` // 第三方用户ID
|
ThirdPartyID string `json:"third_party_id"` // 第三方用户ID
|
||||||
|
ThirdPartyEmail string `json:"third_party_email"` // 第三方平台用户邮箱
|
||||||
ThirdPartyPlatform string `json:"third_party_platform"` // 第三方平台名称,qq,github
|
ThirdPartyPlatform string `json:"third_party_platform"` // 第三方平台名称,qq,github
|
||||||
ThirdPartyUserName string `json:"third_party_user_name"` // 第三方用户名
|
ThirdPartyUserName string `json:"third_party_user_name"` // 第三方用户名
|
||||||
ThirdPartyUserAvatar string `json:"third_party_user_avatar"` // 第三方用户头像
|
ThirdPartyUserAvatar string `json:"third_party_user_avatar"` // 第三方用户头像
|
||||||
|
|
@ -217,7 +218,7 @@ func FindThirdPartyUserInfoByUserID(userID int) []ThirdPartyUserInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据平台用户id获取信息
|
// 根据平台用户id获取信息
|
||||||
func FindThirdPartyUserInfoByThirdPartyID(thirdPartyID int) []ThirdPartyUserInfo {
|
func FindThirdPartyUserInfoByThirdPartyID(thirdPartyID string) []ThirdPartyUserInfo {
|
||||||
var thirdPartyUserInfo []ThirdPartyUserInfo
|
var thirdPartyUserInfo []ThirdPartyUserInfo
|
||||||
DB.Where("third_party_id = ?", thirdPartyID).First(&thirdPartyUserInfo)
|
DB.Where("third_party_id = ?", thirdPartyID).First(&thirdPartyUserInfo)
|
||||||
return thirdPartyUserInfo
|
return thirdPartyUserInfo
|
||||||
|
|
@ -230,7 +231,7 @@ func FindThirdPartyUserInfoByPlatformAndUserID(thirdPartyPlatform string, userID
|
||||||
return thirdPartyUserInfo
|
return thirdPartyUserInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateThirdPartyUserInfo(userID, thirdPartyID int, thirdPartyPlatform, thirdPartyUserName, thirdPartyUserAvatar, thirdPartyUserUrl string) uint {
|
func CreateThirdPartyUserInfo(userID int, thirdPartyID, thirdPartyPlatform, thirdPartyUserName, thirdPartyUserAvatar, thirdPartyUserUrl string) uint {
|
||||||
thirdPartyUserInfo := ThirdPartyUserInfo{UserID: userID, ThirdPartyID: thirdPartyID, ThirdPartyPlatform: thirdPartyPlatform, ThirdPartyUserName: thirdPartyUserName, ThirdPartyUserAvatar: thirdPartyUserAvatar, ThirdPartyUserUrl: thirdPartyUserUrl}
|
thirdPartyUserInfo := ThirdPartyUserInfo{UserID: userID, ThirdPartyID: thirdPartyID, ThirdPartyPlatform: thirdPartyPlatform, ThirdPartyUserName: thirdPartyUserName, ThirdPartyUserAvatar: thirdPartyUserAvatar, ThirdPartyUserUrl: thirdPartyUserUrl}
|
||||||
res := DB.Create(&thirdPartyUserInfo)
|
res := DB.Create(&thirdPartyUserInfo)
|
||||||
if res.Error != nil {
|
if res.Error != nil {
|
||||||
|
|
@ -268,7 +269,7 @@ func DeleteThirdPartyLoginByID(id int, userID int) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新第三方登录用户信息
|
// 更新第三方登录用户信息
|
||||||
func UpdateThirdPartyUserInfoByThirdPartyID(thirdPartyID int, thirdPartyPlatform, thirdPartyUserName, thirdPartyUserAvatar, thirdPartyUserUrl string) error {
|
func UpdateThirdPartyUserInfoByThirdPartyID(thirdPartyID, thirdPartyPlatform, thirdPartyUserName, thirdPartyUserAvatar, thirdPartyUserUrl string) error {
|
||||||
db2 := DB
|
db2 := DB
|
||||||
if proto.Config.SERVER_SQL_LOG {
|
if proto.Config.SERVER_SQL_LOG {
|
||||||
db2 = DB.Debug()
|
db2 = DB.Debug()
|
||||||
|
|
|
||||||
|
|
@ -809,9 +809,9 @@ func GetThirdPartyAuthUrl(c *gin.Context) {
|
||||||
case "google":
|
case "google":
|
||||||
params := url.Values{}
|
params := url.Values{}
|
||||||
params.Add("client_id", worker.GoogleClientID)
|
params.Add("client_id", worker.GoogleClientID)
|
||||||
params.Add("response_type", "code")
|
params.Add("response_type", "token") //直接返回token
|
||||||
params.Add("redirect_uri", "https://pm.ljsea.top/tool/third_party_callback")
|
params.Add("redirect_uri", "https://pm.ljsea.top/tool/third_party_callback")
|
||||||
params.Add("scope", "https://www.googleapis.com/auth/drive.metadata.readonly+https://www.googleapis.com/auth/calendar.readonly")
|
params.Add("scope", "https://www.googleapis.com/auth/userinfo.email+https://www.googleapis.com/auth/userinfo.profile+openid")
|
||||||
params.Add("state", stateBase64Str)
|
params.Add("state", stateBase64Str)
|
||||||
}
|
}
|
||||||
resp.Message = "success"
|
resp.Message = "success"
|
||||||
|
|
@ -844,7 +844,7 @@ func handleThirdPartyCallback(c *gin.Context) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("json unmarshal error:", err)
|
log.Println("json unmarshal error:", err)
|
||||||
} else {
|
} else {
|
||||||
service.DoThirdPartyCallBack(&state, code)
|
service.DoThirdPartyCallBack(c, &state, code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resp.Code = 0
|
resp.Code = 0
|
||||||
|
|
|
||||||
|
|
@ -133,6 +133,15 @@ type GiteeOAuthRequest struct {
|
||||||
GrantType string `json:"grant_type"`
|
GrantType string `json:"grant_type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ThirdPartyUserInfo struct {
|
||||||
|
UserID string `json:"user_id"` // 第三方用户ID
|
||||||
|
Email string `json:"email"` // 第三方平台用户邮箱
|
||||||
|
Avatar string `json:"avatar"` // 第三方平台用户头像
|
||||||
|
Name string `json:"name"` // 第三方平台用户名
|
||||||
|
Url string `json:"url"` // 第三方平台用户主页,可选
|
||||||
|
// 其他信息
|
||||||
|
}
|
||||||
|
|
||||||
// github返回用户信息
|
// github返回用户信息
|
||||||
type GitHubUserInfo struct {
|
type GitHubUserInfo struct {
|
||||||
LoginUserName string `json:"login"` // 用户名
|
LoginUserName string `json:"login"` // 用户名
|
||||||
|
|
@ -141,6 +150,16 @@ type GitHubUserInfo struct {
|
||||||
Url string `json:"url"` // 用户主页
|
Url string `json:"url"` // 用户主页
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GoogleUserInfoResp struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
VerifiedEmail bool `json:"verified_email"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
GivenName string `json:"given_name"`
|
||||||
|
FamilyName string `json:"family_name"`
|
||||||
|
Picture string `json:"picture"`
|
||||||
|
}
|
||||||
|
|
||||||
// 国外服务器负责请求的请求
|
// 国外服务器负责请求的请求
|
||||||
type OnlineServerReq struct {
|
type OnlineServerReq struct {
|
||||||
Type string `json:"type" form:"type"` // 请求类型,get,post
|
Type string `json:"type" form:"type"` // 请求类型,get,post
|
||||||
|
|
@ -168,3 +187,11 @@ type OutlineServerReqResp struct {
|
||||||
Message string `json:"message"` // 响应信息
|
Message string `json:"message"` // 响应信息
|
||||||
Data OutlineServerResp `json:"data"` // 响应数据
|
Data OutlineServerResp `json:"data"` // 响应数据
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// google回调信息
|
||||||
|
type GoogleOAuthCallback struct {
|
||||||
|
Code string `json:"code"` // code
|
||||||
|
AccessToken string `json:"access_token"` // access_token
|
||||||
|
Scope string `json:"scope"` // scope
|
||||||
|
State string `json:"state"` // state
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/golang-jwt/jwt"
|
"github.com/golang-jwt/jwt"
|
||||||
"log"
|
"log"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
@ -335,6 +336,75 @@ func DoGogsCallBack(state *proto.ThirdPartyLoginState, code string) {
|
||||||
|
|
||||||
// 处理第三方登录状态
|
// 处理第三方登录状态
|
||||||
func HandleThirdPartyLoginStatus(state *proto.ThirdPartyLoginState, thirdPartyLoginStatus *proto.ThirdPartyLoginStatus, userInfo *proto.GitHubUserInfo) {
|
func HandleThirdPartyLoginStatus(state *proto.ThirdPartyLoginState, thirdPartyLoginStatus *proto.ThirdPartyLoginStatus, userInfo *proto.GitHubUserInfo) {
|
||||||
|
if state.Type == "login" {
|
||||||
|
//根据第三方平台查找用户
|
||||||
|
thirdPartyUserInfoList := dao.FindThirdPartyUserInfoByThirdPartyID(strconv.Itoa(userInfo.UserID))
|
||||||
|
if thirdPartyUserInfoList == nil || len(thirdPartyUserInfoList) == 0 {
|
||||||
|
thirdPartyLoginStatus.Status = proto.ThirdPartyUserNotBinded //未绑定用户
|
||||||
|
} else {
|
||||||
|
thirdPartyUserInfo := thirdPartyUserInfoList[0]
|
||||||
|
//获取用户信息
|
||||||
|
user := GetUserByIDWithCache(thirdPartyUserInfo.UserID)
|
||||||
|
if user.ID == 0 {
|
||||||
|
thirdPartyLoginStatus.Status = proto.ThirdPartyUserNotBinded
|
||||||
|
log.Println("get user by id error")
|
||||||
|
} else {
|
||||||
|
//成功
|
||||||
|
thirdPartyLoginStatus.Status = proto.SuccessCode
|
||||||
|
thirdPartyLoginStatus.UserInfo.UserID = int(user.ID)
|
||||||
|
thirdPartyLoginStatus.UserInfo.Username = user.Name
|
||||||
|
thirdPartyLoginStatus.UserInfo.Email = user.Email
|
||||||
|
thirdPartyLoginStatus.UserInfo.Token, _ = GenerateJWTToken(int(user.ID), user.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if state.Type == "add" {
|
||||||
|
//根据第三方平台查找用户
|
||||||
|
thirdPartyUserInfoList := dao.FindThirdPartyUserInfoByThirdPartyID(strconv.Itoa(userInfo.UserID))
|
||||||
|
if thirdPartyUserInfoList != nil && len(thirdPartyUserInfoList) > 0 {
|
||||||
|
thirdPartyLoginStatus.Status = 3 //已绑定用户
|
||||||
|
} else {
|
||||||
|
userIDStr := worker.GetRedis("user_add_platform_" + state.UUID)
|
||||||
|
if userIDStr == "" {
|
||||||
|
log.Println("user id is empty")
|
||||||
|
thirdPartyLoginStatus.Status = 2 //未绑定用户
|
||||||
|
} else {
|
||||||
|
//字符串转int
|
||||||
|
userID, _ := strconv.Atoi(userIDStr)
|
||||||
|
//根据用户ID获取用户信息
|
||||||
|
user := GetUserByIDWithCache(userID)
|
||||||
|
if user.ID == 0 {
|
||||||
|
thirdPartyLoginStatus.Status = 4 //添加用户信息错误
|
||||||
|
log.Println("get user by id error")
|
||||||
|
} else {
|
||||||
|
//需要创建数据库记录
|
||||||
|
data := dao.ThirdPartyUserInfo{UserID: userID, ThirdPartyID: strconv.Itoa(userInfo.UserID), ThirdPartyPlatform: state.Platform, ThirdPartyUserAvatar: userInfo.AvatarUrl, ThirdPartyUserName: userInfo.LoginUserName, ThirdPartyUserUrl: userInfo.Url}
|
||||||
|
uid := dao.CreateThirdPartyUserInfoV2(&data)
|
||||||
|
if uid == 0 {
|
||||||
|
log.Println("create third party user info error")
|
||||||
|
thirdPartyLoginStatus.Status = proto.OperationFailed //操作错误
|
||||||
|
} else {
|
||||||
|
//成功
|
||||||
|
thirdPartyLoginStatus.Status = proto.SuccessCode
|
||||||
|
thirdPartyLoginStatus.UserInfo.UserID = int(user.ID)
|
||||||
|
thirdPartyLoginStatus.UserInfo.Username = user.Name
|
||||||
|
thirdPartyLoginStatus.UserInfo.Email = user.Email
|
||||||
|
thirdPartyLoginStatus.UserInfo.Token, _ = GenerateJWTToken(int(user.ID), user.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Println("DoGithubCallBack state type error:", state.Type)
|
||||||
|
thirdPartyLoginStatus.Status = proto.ParameterError //参数错误
|
||||||
|
}
|
||||||
|
//更新userInfo到数据库
|
||||||
|
err := dao.UpdateThirdPartyUserInfoByThirdPartyID(strconv.Itoa(userInfo.UserID), state.Platform, userInfo.LoginUserName, userInfo.AvatarUrl, userInfo.Url)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("update third party user info error:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleThirdPartyLoginStatusV2(state *proto.ThirdPartyLoginState, thirdPartyLoginStatus *proto.ThirdPartyLoginStatus, userInfo *proto.ThirdPartyUserInfo) {
|
||||||
if state.Type == "login" {
|
if state.Type == "login" {
|
||||||
//根据第三方平台查找用户
|
//根据第三方平台查找用户
|
||||||
thirdPartyUserInfoList := dao.FindThirdPartyUserInfoByThirdPartyID(userInfo.UserID)
|
thirdPartyUserInfoList := dao.FindThirdPartyUserInfoByThirdPartyID(userInfo.UserID)
|
||||||
|
|
@ -376,7 +446,7 @@ func HandleThirdPartyLoginStatus(state *proto.ThirdPartyLoginState, thirdPartyLo
|
||||||
log.Println("get user by id error")
|
log.Println("get user by id error")
|
||||||
} else {
|
} else {
|
||||||
//需要创建数据库记录
|
//需要创建数据库记录
|
||||||
data := dao.ThirdPartyUserInfo{UserID: userID, ThirdPartyID: userInfo.UserID, ThirdPartyPlatform: state.Platform, ThirdPartyUserAvatar: userInfo.AvatarUrl, ThirdPartyUserName: userInfo.LoginUserName, ThirdPartyUserUrl: userInfo.Url}
|
data := dao.ThirdPartyUserInfo{UserID: userID, ThirdPartyID: userInfo.UserID, ThirdPartyPlatform: state.Platform, ThirdPartyUserAvatar: userInfo.Avatar, ThirdPartyUserName: userInfo.Name, ThirdPartyUserUrl: userInfo.Url, ThirdPartyEmail: userInfo.Email}
|
||||||
uid := dao.CreateThirdPartyUserInfoV2(&data)
|
uid := dao.CreateThirdPartyUserInfoV2(&data)
|
||||||
if uid == 0 {
|
if uid == 0 {
|
||||||
log.Println("create third party user info error")
|
log.Println("create third party user info error")
|
||||||
|
|
@ -397,13 +467,13 @@ func HandleThirdPartyLoginStatus(state *proto.ThirdPartyLoginState, thirdPartyLo
|
||||||
thirdPartyLoginStatus.Status = proto.ParameterError //参数错误
|
thirdPartyLoginStatus.Status = proto.ParameterError //参数错误
|
||||||
}
|
}
|
||||||
//更新userInfo到数据库
|
//更新userInfo到数据库
|
||||||
err := dao.UpdateThirdPartyUserInfoByThirdPartyID(userInfo.UserID, state.Platform, userInfo.LoginUserName, userInfo.AvatarUrl, userInfo.Url)
|
err := dao.UpdateThirdPartyUserInfoByThirdPartyID(userInfo.UserID, state.Platform, userInfo.Name, userInfo.Avatar, userInfo.Url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("update third party user info error:", err)
|
log.Println("update third party user info error:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func DoThirdPartyCallBack(state *proto.ThirdPartyLoginState, code string) {
|
func DoThirdPartyCallBack(c *gin.Context, state *proto.ThirdPartyLoginState, code string) {
|
||||||
switch state.Platform {
|
switch state.Platform {
|
||||||
case "github":
|
case "github":
|
||||||
DoGithubCallBack(state, code)
|
DoGithubCallBack(state, code)
|
||||||
|
|
@ -415,39 +485,34 @@ func DoThirdPartyCallBack(state *proto.ThirdPartyLoginState, code string) {
|
||||||
// TODO
|
// TODO
|
||||||
log.Println("DoThirdPartyCallBack gogs error:", state.Platform)
|
log.Println("DoThirdPartyCallBack gogs error:", state.Platform)
|
||||||
case "google":
|
case "google":
|
||||||
DoGoogleCallBack(state, code)
|
accessToken := c.Query("access_token")
|
||||||
|
DoGoogleCallBack(state, accessToken)
|
||||||
default:
|
default:
|
||||||
log.Println("DoThirdPartyCallBack platform error:", state.Platform)
|
log.Println("DoThirdPartyCallBack platform error:", state.Platform)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func DoGoogleCallBack(state *proto.ThirdPartyLoginState, code string) {
|
func DoGoogleCallBack(state *proto.ThirdPartyLoginState, accessToken string) {
|
||||||
//获取Access Token
|
|
||||||
resp, err := worker.GetGiteeAccessTokenByCode(code, "https://pm.ljsea.top/tool/gitee_callback", proto.Config.GITEE_CLIENT_ID, proto.Config.GITEE_CLIENT_SECRET)
|
if accessToken == "" {
|
||||||
if err != nil {
|
log.Println("get google access token is empty")
|
||||||
log.Println("get google access token error:", err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if resp.AccessToken == "" {
|
log.Println("get google access token:", accessToken)
|
||||||
log.Println("get gitee access token is empty")
|
|
||||||
log.Println("get gitee access token error:", resp)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.Println("get gitee access token:", resp.AccessToken)
|
|
||||||
//获取用户信息
|
//获取用户信息
|
||||||
userInfo, err := worker.GetGiteeUserInfo(resp.AccessToken)
|
userInfo, err := worker.GetGoogleUserInfo(accessToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("get gitee user info error:", err)
|
log.Println("get google user info error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Println("get gitee user info:", userInfo)
|
log.Println("get github user info:", userInfo)
|
||||||
var thirdPartyLoginStatus proto.ThirdPartyLoginStatus
|
var thirdPartyLoginStatus proto.ThirdPartyLoginStatus
|
||||||
thirdPartyLoginStatus.Type = state.Platform
|
thirdPartyLoginStatus.Type = state.Platform
|
||||||
HandleThirdPartyLoginStatus(state, &thirdPartyLoginStatus, &userInfo)
|
thirdPartyUserInfo := proto.ThirdPartyUserInfo{UserID: userInfo.ID, Name: userInfo.Name, Avatar: userInfo.Picture, Email: userInfo.Email}
|
||||||
|
HandleThirdPartyLoginStatusV2(state, &thirdPartyLoginStatus, &thirdPartyUserInfo)
|
||||||
//更新redis中的第三方登录状态
|
//更新redis中的第三方登录状态
|
||||||
thirdPartyLoginStatusStr, _ := json.Marshal(thirdPartyLoginStatus)
|
thirdPartyLoginStatusStr, _ := json.Marshal(thirdPartyLoginStatus)
|
||||||
log.Println("do handle gitee callback success, third party login status:", string(thirdPartyLoginStatusStr))
|
log.Println("do handle google callback success, third party login status:", string(thirdPartyLoginStatusStr))
|
||||||
worker.SetRedisWithExpire(state.UUID, string(thirdPartyLoginStatusStr), time.Minute*10)
|
worker.SetRedisWithExpire(state.UUID, string(thirdPartyLoginStatusStr), time.Minute*10)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -245,14 +245,31 @@ func GetGoogleAccessTokenByCode(code string, redirectURI string, clientID string
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetGoogleUserInfo(accessToken string) (proto.GitHubUserInfo, error) {
|
func GetGoogleUserInfo(accessToken string) (proto.GoogleUserInfoResp, error) {
|
||||||
var resp proto.GitHubUserInfo
|
var resp proto.GoogleUserInfoResp
|
||||||
|
url := "https://www.googleapis.com/oauth2/v2/userinfo?access_token=" + accessToken
|
||||||
url := "https://www.googleapis.com/oauth2/v1/userinfo?access_token=" + accessToken
|
var onlineReq proto.OnlineServerReq
|
||||||
err, respBytes := DoGetRequest(url, nil)
|
onlineReq.Type = "get"
|
||||||
|
onlineReq.Url = url
|
||||||
|
superTokens := GetRedisSetMembers("super_permission_tokens")
|
||||||
|
onlineReqBytes, _ := json.Marshal(onlineReq)
|
||||||
|
headers := map[string]string{
|
||||||
|
"token": superTokens[0],
|
||||||
|
"super_id": "1",
|
||||||
|
}
|
||||||
|
log.Println("GetGoogleUserInfo onlineReqBytes:", string(onlineReqBytes))
|
||||||
|
err, respBytes := DoPostRequestJSON("https://vis.ljsea.top/tool/online_server_request?super_id=1", onlineReqBytes, headers)
|
||||||
|
log.Println("GetGoogleUserInfo respBytes:", string(respBytes))
|
||||||
|
var onlineResp proto.OutlineServerReqResp
|
||||||
|
err = json.Unmarshal(respBytes, &onlineResp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
err = json.Unmarshal([]byte(onlineResp.Data.Response.Response), &resp)
|
||||||
|
//err, respBytes := DoGetRequest(url, nil)
|
||||||
|
//if err != nil {
|
||||||
|
// return resp, err
|
||||||
|
//}
|
||||||
err = json.Unmarshal(respBytes, &resp)
|
err = json.Unmarshal(respBytes, &resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return resp, err
|
return resp, err
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue