modified: go.mod

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
This commit is contained in:
2025-09-29 22:01:04 +05:00
parent ca37a475c9
commit f7b09e260c
10 changed files with 160 additions and 42 deletions
+3 -6
View File
@@ -3,20 +3,17 @@ module serv_golang_rest_api
go 1.25.1
require (
github.com/golang-jwt/jwt/v4 v4.5.2
golang.org/x/oauth2 v0.31.0
gorm.io/driver/postgres v1.6.0
gorm.io/gorm v1.31.0
)
require (
cloud.google.com/go/compute/metadata v0.3.0 // indirect
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
golang.org/x/oauth2 v0.31.0 // indirect
)
require cloud.google.com/go/compute/metadata v0.3.0 // indirect
require (
github.com/go-chi/chi/v5 v5.2.3
github.com/go-chi/cors v1.2.2
github.com/google/uuid v1.6.0
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.6.0 // indirect
-8
View File
@@ -9,8 +9,6 @@ github.com/go-chi/cors v1.2.2 h1:Jmey33TE+b+rB7fT8MUy1u0I4L+NARQlK6LhzKPSyQE=
github.com/go-chi/cors v1.2.2/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
@@ -30,18 +28,12 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
golang.org/x/oauth2 v0.31.0 h1:8Fq0yVZLh4j4YA47vHKFTa9Ew5XIrCP8LC6UeNZnLxo=
golang.org/x/oauth2 v0.31.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -3,7 +3,7 @@ package handlers
import (
"net/http"
"serv_golang_rest_api/internal/model"
"serv_golang_rest_api/internal/models"
"serv_golang_rest_api/internal/utils"
"gorm.io/gorm"
@@ -32,7 +32,7 @@ func (h *AuthHandler) Register(w http.ResponseWriter, r *http.Request) {
}
// Проверяем, существует ли пользователь
var existingUser model.User
var existingUser models.User
if err := h.DB.Where("email = ?", req.Email).First(&existingUser).Error; err == nil {
utils.WriteError(w, http.StatusConflict, "User already exists")
return
@@ -46,7 +46,7 @@ func (h *AuthHandler) Register(w http.ResponseWriter, r *http.Request) {
}
// Создаем пользователя
user := model.User{
user := models.User{
Email: req.Email,
Password: hashedPassword,
Name: req.Name,
@@ -78,7 +78,7 @@ func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request) {
}
// Ищем пользователя
var user model.User
var user models.User
if err := h.DB.Where("email = ?", req.Email).First(&user).Error; err != nil {
utils.WriteError(w, http.StatusUnauthorized, "Invalid credentials")
return
@@ -0,0 +1,129 @@
// 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
}
@@ -6,7 +6,7 @@ import (
"strconv"
"github.com/go-chi/chi/v5"
"serv_golang_rest_api/internal/model"
"serv_golang_rest_api/internal/models"
"serv_golang_rest_api/internal/service"
)
@@ -19,7 +19,7 @@ func NewUserHandler(userService *service.UserService) *UserHandler {
}
func (h *UserHandler) CreateUser(w http.ResponseWriter, r *http.Request) {
var req model.CreateUserRequest
var req models.CreateUserRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "Invalid request body", http.StatusBadRequest)
return
@@ -1,4 +1,4 @@
package model
package models
import (
"time"
@@ -1,4 +1,4 @@
package model
package models
import (
"time"
@@ -1,7 +1,7 @@
package repository
import (
"serv_golang_rest_api/internal/model"
"serv_golang_rest_api/internal/models"
"gorm.io/gorm"
)
@@ -14,32 +14,32 @@ func NewUserRepository(db *gorm.DB) *UserRepository {
return &UserRepository{db: db}
}
func (r *UserRepository) Create(user *model.User) error {
func (r *UserRepository) Create(user *models.User) error {
return r.db.Create(user).Error
}
func (r *UserRepository) FindByID(id uint) (*model.User, error) {
var user model.User
func (r *UserRepository) FindByID(id uint) (*models.User, error) {
var user models.User
err := r.db.First(&user, id).Error
return &user, err
}
func (r *UserRepository) FindByEmail(email string) (*model.User, error) {
var user model.User
func (r *UserRepository) FindByEmail(email string) (*models.User, error) {
var user models.User
err := r.db.Where("email = ?", email).First(&user).Error
return &user, err
}
func (r *UserRepository) FindAll() ([]model.User, error) {
var users []model.User
func (r *UserRepository) FindAll() ([]models.User, error) {
var users []models.User
err := r.db.Find(&users).Error
return users, err
}
func (r *UserRepository) Update(user *model.User) error {
func (r *UserRepository) Update(user *models.User) error {
return r.db.Save(user).Error
}
func (r *UserRepository) Delete(id uint) error {
return r.db.Delete(&model.User{}, id).Error
return r.db.Delete(&models.User{}, id).Error
}
@@ -2,7 +2,7 @@ package service
import (
"errors"
"serv_golang_rest_api/internal/model"
"serv_golang_rest_api/internal/models"
"serv_golang_rest_api/internal/repository"
"golang.org/x/crypto/bcrypt"
@@ -16,7 +16,7 @@ func NewUserService(userRepo *repository.UserRepository) *UserService {
return &UserService{userRepo: userRepo}
}
func (s *UserService) CreateUser(req *model.CreateUserRequest) (*model.UserResponse, error) {
func (s *UserService) CreateUser(req *models.CreateUserRequest) (*models.UserResponse, error) {
// Проверяем существует ли пользователь с таким email
existingUser, err := s.userRepo.FindByEmail(req.Email)
// Проверяем как на nil, так на пустой ID
@@ -30,7 +30,7 @@ func (s *UserService) CreateUser(req *model.CreateUserRequest) (*model.UserRespo
return nil, err
}
user := &model.User{
user := &models.User{
Name: req.Name,
Email: req.Email,
Password: string(hashedPassword),
@@ -43,7 +43,7 @@ func (s *UserService) CreateUser(req *model.CreateUserRequest) (*model.UserRespo
return s.toUserResponse(user), nil
}
func (s *UserService) GetUserByID(id uint) (*model.UserResponse, error) {
func (s *UserService) GetUserByID(id uint) (*models.UserResponse, error) {
user, err := s.userRepo.FindByID(id)
if err != nil {
return nil, errors.New("user not found")
@@ -52,13 +52,13 @@ func (s *UserService) GetUserByID(id uint) (*model.UserResponse, error) {
return s.toUserResponse(user), nil
}
func (s *UserService) GetAllUsers() ([]model.UserResponse, error) {
func (s *UserService) GetAllUsers() ([]models.UserResponse, error) {
users, err := s.userRepo.FindAll()
if err != nil {
return nil, err
}
var responses []model.UserResponse
var responses []models.UserResponse
for _, user := range users {
responses = append(responses, *s.toUserResponse(&user))
}
@@ -66,8 +66,8 @@ func (s *UserService) GetAllUsers() ([]model.UserResponse, error) {
return responses, nil
}
func (s *UserService) toUserResponse(user *model.User) *model.UserResponse {
return &model.UserResponse{
func (s *UserService) toUserResponse(user *models.User) *models.UserResponse {
return &models.UserResponse{
ID: user.ID,
CreatedAt: user.CreatedAt,
UpdatedAt: user.UpdatedAt,
@@ -4,7 +4,7 @@ import (
"fmt"
"log"
"serv_golang_rest_api/internal/config"
"serv_golang_rest_api/internal/model"
"serv_golang_rest_api/internal/models"
"gorm.io/driver/postgres"
"gorm.io/gorm"
@@ -46,7 +46,7 @@ func autoMigrate(db *gorm.DB) error {
// Или используйте автоматические миграции GORM
return db.AutoMigrate(
&model.User{},
&models.User{},
// другие модели...
)
}