f7b09e260c
modified: go.sum modified: internal/handlers/auth.go new file: internal/handlers/oauth.go modified: internal/handlers/user_handler.go renamed: internal/model/o_auth_provider.go -> internal/models/o_auth_provider.go renamed: internal/model/user.go -> internal/models/user.go modified: internal/repository/user_repository.go modified: internal/service/user_service.go modified: pkg/database/postgres.go add oauth_handler
129 lines
3.9 KiB
Go
129 lines
3.9 KiB
Go
// handlers/oauth.go
|
|
package handlers
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"serv_golang_rest_api/internal/config"
|
|
"serv_golang_rest_api/internal/models"
|
|
"serv_golang_rest_api/internal/utils"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type OAuthHandler struct {
|
|
DB *gorm.DB
|
|
}
|
|
|
|
type GoogleUserInfo struct {
|
|
ID string `json:"id"`
|
|
Email string `json:"email"`
|
|
Name string `json:"name"`
|
|
}
|
|
|
|
type VKUserInfo struct {
|
|
Response []struct {
|
|
ID int `json:"id"`
|
|
FirstName string `json:"first_name"`
|
|
LastName string `json:"last_name"`
|
|
Email string `json:"email"`
|
|
} `json:"response"`
|
|
}
|
|
|
|
func (h *OAuthHandler) GoogleLogin(w http.ResponseWriter, r *http.Request) {
|
|
url := config.GoogleOAuthConfig.AuthCodeURL("state")
|
|
http.Redirect(w, r, url, http.StatusTemporaryRedirect)
|
|
}
|
|
|
|
func (h *OAuthHandler) GoogleCallback(w http.ResponseWriter, r *http.Request) {
|
|
code := r.URL.Query().Get("code")
|
|
|
|
token, err := config.GoogleOAuthConfig.Exchange(r.Context(), code)
|
|
if err != nil {
|
|
utils.WriteError(w, http.StatusBadRequest, "Failed to exchange token")
|
|
return
|
|
}
|
|
|
|
client := config.GoogleOAuthConfig.Client(r.Context(), token)
|
|
resp, err := client.Get("https://www.googleapis.com/oauth2/v2/userinfo")
|
|
if err != nil {
|
|
utils.WriteError(w, http.StatusBadRequest, "Failed to get user info")
|
|
return
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
var userInfo GoogleUserInfo
|
|
if err := json.NewDecoder(resp.Body).Decode(&userInfo); err != nil {
|
|
utils.WriteError(w, http.StatusBadRequest, "Failed to decode user info")
|
|
return
|
|
}
|
|
|
|
// Создаем или находим пользователя
|
|
user, err := h.findOrCreateOAuthUser("google", userInfo.ID, userInfo.Email, userInfo.Name)
|
|
if err != nil {
|
|
utils.WriteError(w, http.StatusInternalServerError, "Error processing user")
|
|
return
|
|
}
|
|
|
|
jwtToken, err := utils.GenerateJWT(user.ID, user.Email)
|
|
if err != nil {
|
|
utils.WriteError(w, http.StatusInternalServerError, "Error generating token")
|
|
return
|
|
}
|
|
|
|
// Редирект или возврат токена
|
|
utils.WriteJSON(w, http.StatusOK, map[string]interface{}{
|
|
"token": jwtToken,
|
|
"user": user,
|
|
})
|
|
}
|
|
|
|
// Аналогичные методы для Yandex и VK...
|
|
|
|
func (h *OAuthHandler) findOrCreateOAuthUser(provider, providerID, email, name string) (*models.User, error) {
|
|
var oauthProvider models.OAuthProvider
|
|
|
|
// Ищем существующую привязку OAuth
|
|
err := h.DB.Where("provider = ? AND provider_id = ?", provider, providerID).
|
|
Preload("User").
|
|
First(&oauthProvider).Error
|
|
|
|
if err == nil {
|
|
// Нашли привязку, теперь загружаем пользователя
|
|
var user models.User
|
|
if err := h.DB.First(&user, oauthProvider.UserID).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return &user, nil
|
|
}
|
|
|
|
// Если привязки нет, ищем пользователя по email
|
|
var user models.User
|
|
err = h.DB.Where("email = ?", email).First(&user).Error
|
|
|
|
if err != nil {
|
|
// Создаем нового пользователя
|
|
user = models.User{
|
|
Email: email,
|
|
Name: name,
|
|
// Генерируем случайный пароль для OAuth пользователей
|
|
Password: utils.GenerateRandomPassword(),
|
|
}
|
|
if err := h.DB.Create(&user).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
// Создаем привязку OAuth
|
|
oauthProvider = models.OAuthProvider{
|
|
UserID: user.ID,
|
|
Provider: provider,
|
|
ProviderID: providerID,
|
|
}
|
|
|
|
if err := h.DB.Create(&oauthProvider).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &user, nil
|
|
} |