116 lines
3.2 KiB
Go
116 lines
3.2 KiB
Go
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
|
|
}
|