From e9e2805e7047d2a7ace55acf91446427ac139376 Mon Sep 17 00:00:00 2001 From: junleea <354425203@qq.com> Date: Tue, 6 May 2025 13:47:44 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E6=B7=BB=E5=8A=A0QQ=E7=AC=AC=E4=B8=89?= =?UTF-8?q?=E6=96=B9=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/inspectionProfiles/Project_Default.xml | 1 + proto/tool.go | 45 +++++++++++++++ service/toolService.go | 32 ++++++++++- worker/thirdParty.go | 60 ++++++++++++++++++++ 4 files changed, 136 insertions(+), 2 deletions(-) diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index 1fec7f8..9db4bea 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -5,6 +5,7 @@ + diff --git a/proto/tool.go b/proto/tool.go index 2617061..295b52a 100644 --- a/proto/tool.go +++ b/proto/tool.go @@ -273,3 +273,48 @@ type StackoverflowUserInfoResponse struct { QuotaMax int `json:"quota_max"` QuotaRemaining int `json:"quota_remaining"` } + +/*********************QQ**************************/ +type QQOAuthRequest struct { + ClientID string `json:"client_id"` + ClientSecret string `json:"client_secret"` + Code string `json:"code"` + RedirectURI string `json:"redirect_uri" ` + //'grant_type': 'authorization_code', + GrantType string `json:"grant_type"` +} + +type QQOAuthTokenResponse struct { + AccessToken string `json:"access_token"` + ExpiresIn int `json:"expires_in"` + RefreshToken string `json:"refresh_token"` +} + +type GetQQOpenIDResponse struct { + ClientID string `json:"client_id"` + OpenID string `json:"openid"` +} + +type QQUserInfoResponse struct { + OpenID string `json:"openid"` + Ret int `json:"ret"` + Msg string `json:"msg"` + IsLost int `json:"is_lost"` + Nickname string `json:"nickname"` + Gender string `json:"gender"` + GenderType int `json:"gender_type"` + Province string `json:"province"` + City string `json:"city"` + Year string `json:"year"` + Figureurl string `json:"figureurl"` + Figureurl1 string `json:"figureurl_1"` + Figureurl2 string `json:"figureurl_2"` + FigureurlQQ1 string `json:"figureurl_qq_1"` + FigureurlQQ2 string `json:"figureurl_qq_2"` + FigureurlQQ string `json:"figureurl_qq"` + IsYellowVip string `json:"is_yellow_vip"` + Vip string `json:"vip"` + YellowVipLevel string `json:"yellow_vip_level"` + Level string `json:"level"` + IsYellowYearVip string `json:"is_yellow_year_vip"` +} diff --git a/service/toolService.go b/service/toolService.go index 4297d19..2a3fc20 100644 --- a/service/toolService.go +++ b/service/toolService.go @@ -479,7 +479,7 @@ func DoThirdPartyCallBack(state *proto.ThirdPartyLoginState, code string) { case "gitee": DoGiteeCallBack(state, code) case "qq": - // TODO + DoQQCallBack(state, code) case "gogs": // TODO log.Println("DoThirdPartyCallBack gogs error:", state.Platform) @@ -488,7 +488,6 @@ func DoThirdPartyCallBack(state *proto.ThirdPartyLoginState, code string) { case "facebook": DoFaceBookCallBack(state, code) case "stackoverflow": - // TODO DoStackoverflowCallBack(state, code) default: log.Println("DoThirdPartyCallBack platform error:", state.Platform) @@ -569,6 +568,7 @@ func DoStackoverflowCallBack(state *proto.ThirdPartyLoginState, code string) { userInfo = userInfoResp.Items[0] thirdPartyUserInfo := proto.ThirdPartyUserInfo{UserID: strconv.Itoa(userInfo.UserID), Name: userInfo.DisplayName, Avatar: userInfo.ProfileImage, Email: ""} HandleThirdPartyLoginStatusV2(state, &thirdPartyLoginStatus, &thirdPartyUserInfo) + thirdPartyLoginStatus.Status = proto.SuccessCode } else { log.Println("get Stackoverflow user info is empty") thirdPartyLoginStatus.Status = proto.ParameterError @@ -581,6 +581,34 @@ func DoStackoverflowCallBack(state *proto.ThirdPartyLoginState, code string) { worker.SetRedisWithExpire(state.UUID, string(thirdPartyLoginStatusStr), time.Minute*10) } +func DoQQCallBack(state *proto.ThirdPartyLoginState, code string) { + var thirdPartyLoginStatus proto.ThirdPartyLoginStatus + thirdPartyLoginStatus.Type = state.Platform + //根据code获取Access Token + tokenResp, err := worker.GetQQAccessTokenByCode(code, "https://www.ljsea.top/qq_callback.php", worker.QQClientID, worker.QQClientSecret) + if tokenResp.AccessToken == "" { + log.Println("get QQ access token is empty") + thirdPartyLoginStatus.Status = proto.ParameterError + } else { + log.Println("get QQ access token:", tokenResp) + //获取用户信息 + userInfo, err2 := worker.GetQQUserInfo(tokenResp.AccessToken) + if err2 != nil { + log.Println("get QQ user info error:", err) + thirdPartyLoginStatus.Status = proto.ParameterError + } else { + log.Println("get QQ user info:", userInfo) + thirdPartyUserInfo := proto.ThirdPartyUserInfo{UserID: userInfo.OpenID, Name: userInfo.Nickname, Avatar: userInfo.Figureurl, Email: ""} + HandleThirdPartyLoginStatusV2(state, &thirdPartyLoginStatus, &thirdPartyUserInfo) + thirdPartyLoginStatus.Status = proto.SuccessCode + } + } + //更新redis中的第三方登录状态 + thirdPartyLoginStatusStr, _ := json.Marshal(thirdPartyLoginStatus) + log.Println("do handle Stackoverflow callback success, third party login status:", string(thirdPartyLoginStatusStr)) + worker.SetRedisWithExpire(state.UUID, string(thirdPartyLoginStatusStr), time.Minute*10) +} + // 国外服务器处理国内服务器要请求外网的请求 func DoRequestToForeignServer(req *proto.OnlineServerReq) (proto.OutlineServerResp, error) { var resp proto.OutlineServerResp diff --git a/worker/thirdParty.go b/worker/thirdParty.go index bd0384f..9337fc0 100644 --- a/worker/thirdParty.go +++ b/worker/thirdParty.go @@ -453,3 +453,63 @@ func GetStackoverflowUserInfo(accessToken string) (proto.StackoverflowUserInfoRe } return resp, nil } + +const ( + QQClientID = "102774740" + QQClientSecret = "iIfpkRuAF8rPn13q" +) + +func GetQQAccessTokenByCode(code string, redirectURI string, clientID string, clientSecret string) (proto.QQOAuthTokenResponse, error) { + req := proto.QQOAuthRequest{ + ClientID: clientID, + ClientSecret: clientSecret, + Code: code, + RedirectURI: redirectURI, + GrantType: "authorization_code", + } + var resp proto.QQOAuthTokenResponse + url := "https://graph.qq.com/oauth2.0/token" + url = fmt.Sprintf("%s?grant_type=%s&client_id=%s&client_secret=%s&code=%s&redirect_uri=%s&fmt=json", url, req.GrantType, req.ClientID, req.ClientSecret, req.Code, req.RedirectURI) + + err2, respBytes := DoGetRequest(url, nil) + if err2 != nil { + return resp, err2 + } + err := json.Unmarshal(respBytes, &resp) + if err != nil { + return resp, err + } + return resp, nil +} + +func GetQQUserInfo(accessToken string) (proto.QQUserInfoResponse, error) { + var resp proto.QQUserInfoResponse + + var openIDInfo proto.GetQQOpenIDResponse + //先获取openid + url := fmt.Sprintf("https://graph.qq.com/oauth2.0/me?access_token=%s&fmt=json", accessToken) + err2, respBytes := DoGetRequest(url, nil) + if err2 != nil { + log.Println("GetQQUserInfo get openid err:", err2) + return resp, err2 + } + err := json.Unmarshal(respBytes, &openIDInfo) + if err != nil { + return resp, err + } + + //如果openid获取成功,获取用户信息 + url = fmt.Sprintf("https://graph.qq.com/user/get_user_info?access_token=%s&oauth_consumer_key=%s&openid=%s&fmt=json", accessToken, QQClientID, openIDInfo.OpenID) + err3, respBytes2 := DoGetRequest(url, nil) + if err3 != nil { + log.Println("GetQQUserInfo get user info err:", err2) + return resp, err2 + } + err = json.Unmarshal(respBytes2, &resp) + if err != nil { + return resp, err + } + resp.OpenID = openIDInfo.OpenID + return resp, nil + +} From ea10d66e1c587ee0adeee2199d247ba3ad2a1412 Mon Sep 17 00:00:00 2001 From: junleea <354425203@qq.com> Date: Tue, 6 May 2025 13:49:06 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E6=B7=BB=E5=8A=A0QQ=E7=AC=AC=E4=B8=89?= =?UTF-8?q?=E6=96=B9=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- handler/tool.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/handler/tool.go b/handler/tool.go index 7914d53..2797bd1 100644 --- a/handler/tool.go +++ b/handler/tool.go @@ -786,8 +786,9 @@ func GetThirdPartyAuthUrl(c *gin.Context) { case "qq": params := url.Values{} params.Add("response_type", "code") - params.Add("client_id", worker.AppId) + params.Add("client_id", worker.QQClientID) params.Add("state", stateBase64Str) + params.Add("redirect_uri", "https://www.ljsea.top/qq_callback.php") str := fmt.Sprintf("%s", params.Encode()) respUrl = fmt.Sprintf("%s?%s", proto.QQAuthorizeBaseUrl, str) case "github":