diff --git a/begushiybashkir/bbvue/src/stores/auth.js b/begushiybashkir/bbvue/src/stores/auth.js index 18d05fa..14c8150 100644 --- a/begushiybashkir/bbvue/src/stores/auth.js +++ b/begushiybashkir/bbvue/src/stores/auth.js @@ -119,7 +119,7 @@ export const useAuthStore = defineStore('auth', () => { setUser(response.data) return { success: true, data: response.data } } catch (err) { - error.value = err.response?.data?.message || 'Ошибка загрузки профиля' + error.value = err.response?.data?.message || err.message || 'Ошибка загрузки профиля' clearToken() clearUser() return { success: false, error: error.value } diff --git a/begushiybashkir/bbvue/src/views/Register.vue b/begushiybashkir/bbvue/src/views/Register.vue index b6c1e35..830b7ff 100644 --- a/begushiybashkir/bbvue/src/views/Register.vue +++ b/begushiybashkir/bbvue/src/views/Register.vue @@ -208,7 +208,8 @@ export default { goals: '', agreeTerms: false, newsletter: true - } + }, + showDebugInfo: import.meta.env.DEV // Показывать отладочную информацию только в development } }, computed: { @@ -249,11 +250,15 @@ export default { newsletter: this.formData.newsletter } + console.log('Отправка данных регистрации:', { ...registerData, password: '***' }) + const result = await this.authStore.register(registerData) if (result.success) { // Перенаправляем на страницу профиля после успешной регистрации this.$router.push('/profile') + } else { + console.error('Ошибка регистрации:', result.error) } } } diff --git a/serv_nginx/api_bb/internal/handlers/auth.go b/serv_nginx/api_bb/internal/handlers/auth.go index 2811770..4b52157 100644 --- a/serv_nginx/api_bb/internal/handlers/auth.go +++ b/serv_nginx/api_bb/internal/handlers/auth.go @@ -3,13 +3,14 @@ package handlers import ( "encoding/json" + "fmt" "net/http" "time" "go-rest-api/internal/models" "go-rest-api/internal/service" "go-rest-api/pkg/middleware" - "go-rest-api/pkg/utils" + "go-rest-api/pkg/utils" "github.com/go-chi/chi/v5" ) @@ -29,17 +30,17 @@ func NewAuthHandler(authService service.AuthService, jwtService service.JWTServi func (h *AuthHandler) Routes() chi.Router { r := chi.NewRouter() - // Обработка OPTIONS запросов для CORS + // Обработка OPTIONS запросов для CORS r.Options("/register", h.handleOptions) r.Options("/login", h.handleOptions) r.Options("/logout", h.handleOptions) r.Options("/profile", h.handleOptions) - + r.Post("/register", h.Register) r.Post("/login", h.Login) r.Post("/logout", h.Logout) r.Get("/profile", h.GetProfile) - + return r } @@ -51,16 +52,15 @@ func (h *AuthHandler) handleOptions(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) } - type RegisterRequest struct { - Email string `json:"email"` - Password string `json:"password"` - FirstName string `json:"first_name"` - LastName string `json:"last_name"` - Phone string `json:"phone"` - Experience string `json:"experience"` - Goals string `json:"goals"` - Newsletter bool `json:"newsletter"` + Email string `json:"email"` + Password string `json:"password"` + FirstName string `json:"first_name"` + LastName string `json:"last_name"` + Phone string `json:"phone"` + Experience string `json:"experience"` + Goals string `json:"goals"` + Newsletter bool `json:"newsletter"` } type LoginRequest struct { @@ -69,28 +69,39 @@ type LoginRequest struct { } type UserResponse struct { - ID uint `json:"id"` - Email string `json:"email"` - FirstName string `json:"first_name"` - LastName string `json:"last_name"` - Phone string `json:"phone"` - Experience string `json:"experience"` - Goals string `json:"goals"` - Newsletter bool `json:"newsletter"` - Role string `json:"role"` + ID uint `json:"id"` + Email string `json:"email"` + FirstName string `json:"first_name"` + LastName string `json:"last_name"` + Phone string `json:"phone"` + Experience string `json:"experience"` + Goals string `json:"goals"` + Newsletter bool `json:"newsletter"` + Role string `json:"role"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` } func (h *AuthHandler) Register(w http.ResponseWriter, r *http.Request) { + + fmt.Printf("Register request: %+v\n", r) + // Устанавливаем CORS заголовки w.Header().Set("Access-Control-Allow-Origin", r.Header.Get("Origin")) w.Header().Set("Access-Control-Allow-Credentials", "true") var req RegisterRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { - utils.RespondWithError(w, http.StatusBadRequest, "Invalid request payload") + utils.RespondWithError(w, http.StatusBadRequest, "Invalid request payload: "+err.Error()) return } - + + // Валидация обязательных полей + if req.FirstName == "" || req.LastName == "" || req.Email == "" || req.Password == "" { + utils.RespondWithError(w, http.StatusBadRequest, "First name, last name, email and password are required") + return + } + user := &models.User{ Email: req.Email, Password: req.Password, @@ -101,15 +112,19 @@ func (h *AuthHandler) Register(w http.ResponseWriter, r *http.Request) { Goals: req.Goals, Newsletter: req.Newsletter, Role: "user", + CreatedAt: time.Now(), + UpdatedAt: time.Now(), } - + if err := h.authService.Register(user); err != nil { utils.RespondWithError(w, http.StatusBadRequest, err.Error()) return } - - utils.RespondWithJSON(w, http.StatusCreated, map[string]string{ + + // После успешной регистрации возвращаем данные пользователя + utils.RespondWithJSON(w, http.StatusCreated, map[string]interface{}{ "message": "User registered successfully", + "user": toUserResponse(user), }) } @@ -117,30 +132,36 @@ func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request) { // Устанавливаем CORS заголовки w.Header().Set("Access-Control-Allow-Origin", r.Header.Get("Origin")) w.Header().Set("Access-Control-Allow-Credentials", "true") - + var req LoginRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { - utils.RespondWithError(w, http.StatusBadRequest, "Invalid request payload") + utils.RespondWithError(w, http.StatusBadRequest, "Invalid request payload: "+err.Error()) return } - + + // Валидация + if req.Email == "" || req.Password == "" { + utils.RespondWithError(w, http.StatusBadRequest, "Email and password are required") + return + } + user, token, err := h.authService.Login(req.Email, req.Password) if err != nil { utils.RespondWithError(w, http.StatusUnauthorized, err.Error()) return } - + // Устанавливаем токен в куки http.SetCookie(w, &http.Cookie{ Name: "auth_token", Value: token, Path: "/", HttpOnly: true, - Secure: false, // В production установить true :TODO + Secure: false, // В production установить true SameSite: http.SameSiteLaxMode, Expires: time.Now().Add(24 * time.Hour), }) - + utils.RespondWithJSON(w, http.StatusOK, map[string]interface{}{ "message": "Login successful", "token": token, @@ -164,7 +185,7 @@ func (h *AuthHandler) Logout(w http.ResponseWriter, r *http.Request) { Expires: time.Now().Add(-1 * time.Hour), MaxAge: -1, }) - + utils.RespondWithJSON(w, http.StatusOK, map[string]string{ "message": "Logout successful", }) @@ -174,13 +195,13 @@ func (h *AuthHandler) GetProfile(w http.ResponseWriter, r *http.Request) { // Устанавливаем CORS заголовки w.Header().Set("Access-Control-Allow-Origin", r.Header.Get("Origin")) w.Header().Set("Access-Control-Allow-Credentials", "true") - + user, ok := middleware.GetUserFromContext(r.Context()) if !ok { utils.RespondWithError(w, http.StatusUnauthorized, "Authentication required") return } - + utils.RespondWithJSON(w, http.StatusOK, toUserResponse(user)) } @@ -195,5 +216,7 @@ func toUserResponse(user *models.User) UserResponse { Goals: user.Goals, Newsletter: user.Newsletter, Role: user.Role, + CreatedAt: user.CreatedAt, + UpdatedAt: user.UpdatedAt, } -} \ No newline at end of file +} diff --git a/serv_nginx/api_bb/internal/models/user.go b/serv_nginx/api_bb/internal/models/user.go index ec8b400..6395931 100644 --- a/serv_nginx/api_bb/internal/models/user.go +++ b/serv_nginx/api_bb/internal/models/user.go @@ -37,4 +37,21 @@ func (u *User) HashPassword() error { func (u *User) CheckPassword(password string) bool { err := bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(password)) return err == nil +} + +// BeforeCreate hook для GORM +func (u *User) BeforeCreate(tx *gorm.DB) error { + if u.CreatedAt.IsZero() { + u.CreatedAt = time.Now() + } + if u.UpdatedAt.IsZero() { + u.UpdatedAt = time.Now() + } + return u.HashPassword() +} + +// BeforeUpdate hook для GORM +func (u *User) BeforeUpdate(tx *gorm.DB) error { + u.UpdatedAt = time.Now() + return nil } \ No newline at end of file diff --git a/serv_nginx/api_bb/internal/service/auth_service.go b/serv_nginx/api_bb/internal/service/auth_service.go index 8771b98..8927327 100644 --- a/serv_nginx/api_bb/internal/service/auth_service.go +++ b/serv_nginx/api_bb/internal/service/auth_service.go @@ -32,11 +32,28 @@ func (s *authService) Register(user *models.User) error { if err == nil && existingUser != nil { return errors.New("user with this email already exists") } - - // Хешируем пароль - if err := user.HashPassword(); err != nil { - return err + + // Валидация обязательных полей + if user.FirstName == "" { + return errors.New("first name is required") } + if user.LastName == "" { + return errors.New("last name is required") + } + if user.Email == "" { + return errors.New("email is required") + } + if user.Password == "" { + return errors.New("password is required") + } + if len(user.Password) < 6 { + return errors.New("password must be at least 6 characters") + } + + // Хешируем пароль (будет вызван в BeforeCreate hook) + // if err := user.HashPassword(); err != nil { + // return err + // } return s.userRepo.Create(user) }