From 5526a88d94fa9babd1afeb475b81357e27f5c2af Mon Sep 17 00:00:00 2001 From: junleea <354425203@qq.com> Date: Mon, 28 Apr 2025 13:14:51 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AC=AC=E4=B8=89=E6=96=B9=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0gitee?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- handler/tool.go | 34 ++++++++++++ proto/conf.go | 2 + proto/status.go | 1 + proto/tool.go | 20 +++++++ service/toolService.go | 123 ++++++++++++++++++++++++++--------------- worker/gitee.go | 46 +++++++++++++++ 6 files changed, 181 insertions(+), 45 deletions(-) create mode 100644 worker/gitee.go diff --git a/handler/tool.go b/handler/tool.go index cbb4de7..bd59b2e 100644 --- a/handler/tool.go +++ b/handler/tool.go @@ -61,6 +61,7 @@ func SetUpToolGroup(router *gin.Engine) { toolGroup.GET("/github_auth", GetGithubAuthUrl) toolGroup.GET("/get_auth_url", GetThirdPartyAuthUrl) toolGroup.GET("/github_callback", handleGithubCallback) + toolGroup.GET("/gitee_callback", handleGiteeCallback) toolGroup.POST("/loginRedirect", LoginRedirect) //发送邮件 toolGroup.POST("/send_mail", SendMailTool) @@ -666,6 +667,30 @@ func handleGithubCallback(c *gin.Context) { c.JSON(http.StatusOK, resp) } +func handleGiteeCallback(c *gin.Context) { + var resp proto.GenerateResp + code := c.Query("code") //code + stateBase64Str := c.Query("state") //state + //解析base64 + decodedBytes, err := base64.StdEncoding.DecodeString(stateBase64Str) + if err != nil { + fmt.Println("Decoding error:", err) + } else { + decodedStr := string(decodedBytes) + //json解析 + var state proto.ThirdPartyLoginState + err = json.Unmarshal([]byte(decodedStr), &state) + log.Println("handle github callback state:", decodedStr, "\tcode:", code) + if err != nil { + log.Println("json unmarshal error:", err) + } + service.DoGiteeCallBack(&state, code) + } + resp.Code = 0 + resp.Message = "success" + c.JSON(http.StatusOK, resp) +} + func GetGithubAuthUrl(c *gin.Context) { uuid := c.Query("uuid") hType := c.Query("type") //操作类型add,login @@ -763,6 +788,15 @@ func GetThirdPartyAuthUrl(c *gin.Context) { params.Add("state", stateBase64Str) baseUri := proto.GitHuAuthorizeBaseUrl respUrl = fmt.Sprintf("%s?%s", baseUri, params.Encode()) + case "gitee": + params := url.Values{} + params.Add("client_id", proto.Config.GITEE_CLIENT_ID) + //response_type=code + params.Add("response_type", "code") + params.Add("state", stateBase64Str) + //params.Add("redirect_uri", "https://pm.ljsea.top/tool/gitee_callback") + baseUri := proto.GiteeAuthorizeBaseUrl + respUrl = fmt.Sprintf("%s?%s", baseUri, params.Encode()) } resp.Message = "success" resp.Code = proto.SuccessCode diff --git a/proto/conf.go b/proto/conf.go index 1cf157b..500e704 100644 --- a/proto/conf.go +++ b/proto/conf.go @@ -87,6 +87,8 @@ type ConfigStruct struct { KBASE_SERVER []KBaseServer `json:"kbase_server"` // 知识库服务器列表 GITHUB_CLIENT_ID string `json:"github_client_id"` // github client id GITHUB_CLIENT_SECRET string `json:"github_client_secret"` // github client secret + GITEE_CLIENT_ID string `json:"gitee_client_id"` // gitee client id + GITEE_CLIENT_SECRET string `json:"gitee_client_secret"` // gitee client secret } type KBaseServer struct { diff --git a/proto/status.go b/proto/status.go index 991aef2..a227c28 100644 --- a/proto/status.go +++ b/proto/status.go @@ -191,4 +191,5 @@ const ( const ( GitHuAuthorizeBaseUrl = "https://github.com/login/oauth/authorize" QQAuthorizeBaseUrl = "https://graph.qq.com/oauth2.0/authorize" + GiteeAuthorizeBaseUrl = "https://gitee.com/oauth/authorize" ) diff --git a/proto/tool.go b/proto/tool.go index f80fdf4..4292273 100644 --- a/proto/tool.go +++ b/proto/tool.go @@ -79,6 +79,10 @@ type ThirdPartyLoginState struct { UserID int `json:"user_id"` // 用户ID,当为add时需要 } +type OAuthResponse struct { + AccessToken string `json:"access_token"` // access_token +} + // github type GitHubOAuthResponse struct { AccessToken string `json:"access_token"` @@ -86,6 +90,22 @@ type GitHubOAuthResponse struct { TokenType string `json:"token_type"` } +type GiteeOAuthTokenResponse struct { + AccessToken string `json:"access_token"` + TokenType string `json:"token_type"` + ExpiresIn int `json:"expires_in"` + RefreshToken string `json:"refresh_token"` + Scope string `json:"scope"` + CreatedAt int `json:"created_at"` +} + +type OAuthGetTokenRequest struct { + ClientID string `json:"client_id"` + ClientSecret string `json:"client_secret"` + Code string `json:"code"` + RedirectURI string `json:"redirect_uri" ` +} + type GitHubOAuthRequest struct { ClientID string `json:"client_id"` ClientSecret string `json:"client_secret"` diff --git a/service/toolService.go b/service/toolService.go index 2cdd476..7551e53 100644 --- a/service/toolService.go +++ b/service/toolService.go @@ -225,6 +225,84 @@ func DoGithubCallBack(state *proto.ThirdPartyLoginState, code string) { log.Println("get github user info:", userInfo) var thirdPartyLoginStatus proto.ThirdPartyLoginStatus thirdPartyLoginStatus.Type = state.Platform + HandleThirdPartyLoginStatus(state, &thirdPartyLoginStatus, &userInfo) //处理第三方登录状态 + //更新redis中的第三方登录状态 + thirdPartyLoginStatusStr, _ := json.Marshal(thirdPartyLoginStatus) + log.Println("do handle github callback success, third party login status:", string(thirdPartyLoginStatusStr)) + worker.SetRedisWithExpire(state.UUID, string(thirdPartyLoginStatusStr), time.Minute*10) +} + +// 解析jwt内容 +func DecodeJWTToken(tokenStr string) (int, error) { + //解析jwt + // 使用加密secret 解析 JWT 令牌 + token, err := jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) { + return proto.SigningKey, nil + }) + if err != nil { + return 0, err + } + // 验证令牌 + if !token.Valid { + return 0, fmt.Errorf("invalid token") + } + // 获取用户ID + claims, ok := token.Claims.(jwt.MapClaims) + if !ok { + return 0, fmt.Errorf("invalid token claims") + } + userID, ok := claims["id"].(float64) + if !ok { + return 0, fmt.Errorf("invalid token claims") + } + return int(userID), nil +} + +// 生成token +func GenerateJWTToken(userID int, userName string) (string, error) { + //创建token + claims := jwt.MapClaims{ + "id": userID, + "username": userName, + } + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + tokenString, err := token.SignedString(proto.SigningKey) + if err != nil { + return "", err + } + return tokenString, nil +} + +func DoGiteeCallBack(state *proto.ThirdPartyLoginState, code string) { + //获取Access Token + resp, err := worker.GetGiteeAccessTokenByCode(code, "https://pm.ljsea.top/gitee_callback", proto.Config.GITEE_CLIENT_ID, proto.Config.GITEE_CLIENT_SECRET) + if err != nil { + log.Println("get gitee access token error:", err) + return + } + if resp.AccessToken == "" { + log.Println("get gitee access token is empty") + return + } + log.Println("get gitee access token:", resp.AccessToken) + //获取用户信息 + userInfo, err := worker.GetGiteeUserInfo(resp.AccessToken) + if err != nil { + log.Println("get gitee user info error:", err) + return + } + log.Println("get gitee user info:", userInfo) + var thirdPartyLoginStatus proto.ThirdPartyLoginStatus + thirdPartyLoginStatus.Type = state.Platform + HandleThirdPartyLoginStatus(state, &thirdPartyLoginStatus, &userInfo) + //更新redis中的第三方登录状态 + thirdPartyLoginStatusStr, _ := json.Marshal(thirdPartyLoginStatus) + log.Println("do handle github callback success, third party login status:", string(thirdPartyLoginStatusStr)) + worker.SetRedisWithExpire(state.UUID, string(thirdPartyLoginStatusStr), time.Minute*10) +} + +// 处理第三方登录状态 +func HandleThirdPartyLoginStatus(state *proto.ThirdPartyLoginState, thirdPartyLoginStatus *proto.ThirdPartyLoginStatus, userInfo *proto.GitHubUserInfo) { if state.Type == "login" { //根据第三方平台查找用户 thirdPartyUserInfoList := dao.FindThirdPartyUserInfoByThirdPartyID(userInfo.UserID) @@ -286,49 +364,4 @@ func DoGithubCallBack(state *proto.ThirdPartyLoginState, code string) { log.Println("DoGithubCallBack state type error:", state.Type) thirdPartyLoginStatus.Status = proto.ParameterError //参数错误 } - //更新redis中的第三方登录状态 - thirdPartyLoginStatusStr, _ := json.Marshal(thirdPartyLoginStatus) - log.Println("do handle github callback success, third party login status:", string(thirdPartyLoginStatusStr)) - worker.SetRedisWithExpire(state.UUID, string(thirdPartyLoginStatusStr), time.Minute*10) -} - -// 解析jwt内容 -func DecodeJWTToken(tokenStr string) (int, error) { - //解析jwt - // 使用加密secret 解析 JWT 令牌 - token, err := jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) { - return proto.SigningKey, nil - }) - if err != nil { - return 0, err - } - // 验证令牌 - if !token.Valid { - return 0, fmt.Errorf("invalid token") - } - // 获取用户ID - claims, ok := token.Claims.(jwt.MapClaims) - if !ok { - return 0, fmt.Errorf("invalid token claims") - } - userID, ok := claims["id"].(float64) - if !ok { - return 0, fmt.Errorf("invalid token claims") - } - return int(userID), nil -} - -// 生成token -func GenerateJWTToken(userID int, userName string) (string, error) { - //创建token - claims := jwt.MapClaims{ - "id": userID, - "username": userName, - } - token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) - tokenString, err := token.SignedString(proto.SigningKey) - if err != nil { - return "", err - } - return tokenString, nil } diff --git a/worker/gitee.go b/worker/gitee.go new file mode 100644 index 0000000..b0447e4 --- /dev/null +++ b/worker/gitee.go @@ -0,0 +1,46 @@ +package worker + +import ( + "StuAcaWorksAI/proto" + "encoding/json" +) + +func GetGiteeAccessTokenByCode(code string, redirectURI string, clientID string, clientSecret string) (proto.GiteeOAuthTokenResponse, error) { + req := proto.OAuthGetTokenRequest{ + ClientID: clientID, + ClientSecret: clientSecret, + Code: code, + RedirectURI: redirectURI, + } + var resp proto.GiteeOAuthTokenResponse + reqBytes, err := json.Marshal(req) + if err != nil { + return resp, err + } + url := "https://gitee.com/oauth/token" + + err2, respBytes := DoPostRequestJSON(url, reqBytes, nil) + if err2 != nil { + return resp, err2 + } + err = json.Unmarshal(respBytes, &resp) + if err != nil { + return resp, err + } + return resp, nil +} + +func GetGiteeUserInfo(accessToken string) (proto.GitHubUserInfo, error) { + url := "https://gitee.com/api/v5/user?access_token=" + accessToken + var resp proto.GitHubUserInfo + 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 + +}