Merge branch 'refs/heads/feat-login-website'

This commit is contained in:
junleea 2025-05-06 13:49:12 +08:00
commit 933b969ad9
5 changed files with 138 additions and 3 deletions

View File

@ -5,6 +5,7 @@
<functions>
<function importPath="net/http" name="NewRequest" />
<function importPath="StuAcaWorksAI/worker" name="GetStackoverflowAccessTokenByCode" />
<function importPath="StuAcaWorksAI/worker" name="GetQQAccessTokenByCode" />
</functions>
</inspection_tool>
</profile>

View File

@ -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":

View File

@ -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"`
}

View File

@ -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

View File

@ -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
}