package oauth import ( "context" "encoding/json" "esauth/pkg/repository" "esauth/pkg/service" "esauth/pkg/util" "fmt" "net/http" "strings" "github.com/gin-gonic/gin" "golang.org/x/oauth2" ) type GoogleOAuth struct { Service *service.Service Repo *repository.Repository GoogleOauthConfig *oauth2.Config } const GOOGLE_RANDOM_STATE = "xeiojqj433DS" // Строка состояния для защиты от CSRF // Обработка колбэка с авторизацией func (g GoogleOAuth) HandleGoogleCallback(c *gin.Context) { // Проверяем состояние (state) для защиты от CSRF атак if c.Query("state") != GOOGLE_RANDOM_STATE { util.NewErrorResponse(c, http.StatusInternalServerError, "Invalid OAuth state") return } // Получаем код авторизации от Google code := c.Query("code") if code == "" { util.NewErrorResponse(c, http.StatusInternalServerError, "Code not found") return } // Обмен кода авторизации на токен token, err := g.GoogleOauthConfig.Exchange(context.Background(), code) if err != nil { util.NewErrorResponse(c, http.StatusInternalServerError, "Failed to exchange token") return } // Получаем информацию о пользователе с помощью токена userInfo, err := getUserInfo(token.AccessToken) if err != nil { util.NewErrorResponse(c, http.StatusInternalServerError, "Failed to get user info") return } id, _ := userInfo["id"].(string) user, _ := g.Repo.FindUser("google_id = ?", id) usertoken := c.Query("usertoken") currentUserId, err := g.Service.ParseToken(usertoken) if err == nil { currentUser, _ := g.Repo.GetUser(currentUserId) if (user.Id != currentUser.Id) && (user.Id != 0) { util.NewErrorResponse(c, http.StatusInternalServerError, fmt.Sprintf("This account already conntected to user %d", user.Id)) return } user = currentUser } if user.Username == "" { username, _ := userInfo["name"].(string) user.Username = strings.ReplaceAll(username, " ", "") } if user.FirstName == "" { user.FirstName, _ = userInfo["given_name"].(string) } if user.LastName == "" { user.LastName, _ = userInfo["family_name"].(string) } if user.PictureURL == "" { user.PictureURL, _ = userInfo["picture"].(string) } if user.Email == "" { user.Email, _ = userInfo["email"].(string) } user.GoogleId = id _, err = g.Service.CreateUser(&user) if err != nil { g.Service.SaveUser(&user) } tkn, err := g.Service.GenerateToken(user.Id) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.Redirect(http.StatusMovedPermanently, "/?token="+tkn) c.Abort() } // getUserInfo получает информацию о пользователе через Google API func getUserInfo(accessToken string) (map[string]interface{}, error) { resp, err := http.Get(fmt.Sprintf("https://www.googleapis.com/oauth2/v2/userinfo?access_token=%s", accessToken)) if err != nil { return nil, err } defer resp.Body.Close() var userInfo map[string]interface{} if err := json.NewDecoder(resp.Body).Decode(&userInfo); err != nil { return nil, err } return userInfo, nil }