144 lines
3.7 KiB
Go
144 lines
3.7 KiB
Go
package controllers
|
|
|
|
import (
|
|
"github.com/gofiber/fiber/v2"
|
|
"github.com/golang-jwt/jwt"
|
|
"golang.org/x/crypto/bcrypt"
|
|
"log"
|
|
"main/database"
|
|
"main/models"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/joho/godotenv"
|
|
)
|
|
|
|
// Глобальная переменная для хранения ключа
|
|
var SecretKey string
|
|
|
|
func init() {
|
|
// Загружаем .env файл
|
|
err := godotenv.Load()
|
|
if err != nil {
|
|
log.Fatal("Ошибка загрузки .env файла")
|
|
}
|
|
|
|
// Читаем ключ из переменной окружения
|
|
SecretKey = os.Getenv("JWT_SECRET_KEY")
|
|
if SecretKey == "" {
|
|
log.Fatal("JWT_SECRET_KEY не задан в .env")
|
|
}
|
|
}
|
|
|
|
// Регистрируем пользователя
|
|
func Register(c *fiber.Ctx) error {
|
|
var data map[string]string
|
|
if err := c.BodyParser(&data); err != nil {
|
|
return err
|
|
}
|
|
|
|
if data["password"] == "" {
|
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"message": "Password is required"})
|
|
}
|
|
|
|
// Проверка на существующего пользователя
|
|
var existingUser models.User
|
|
if err := database.DB.Where("email = ?", data["email"]).First(&existingUser).Error; err == nil {
|
|
return c.Status(fiber.StatusConflict).JSON(fiber.Map{"message": "Email already taken"})
|
|
}
|
|
|
|
password, _ := bcrypt.GenerateFromPassword([]byte(data["password"]), bcrypt.DefaultCost)
|
|
user := models.User{
|
|
Name: data["name"],
|
|
Email: data["email"],
|
|
Password: password,
|
|
}
|
|
|
|
database.DB.Create(&user)
|
|
|
|
return c.JSON(user)
|
|
}
|
|
|
|
// Генерация JWT-токена
|
|
func generateToken(user models.User) (string, error) {
|
|
claims := jwt.MapClaims{
|
|
"user_id": user.Id,
|
|
"exp": time.Now().Add(time.Hour * 24).Unix(), // Токен на 24 часа
|
|
}
|
|
|
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
|
return token.SignedString([]byte(SecretKey))
|
|
}
|
|
|
|
func Login(c *fiber.Ctx) error {
|
|
var data map[string]string
|
|
if err := c.BodyParser(&data); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Найти пользователя по email
|
|
var user models.User
|
|
database.DB.Where("email = ?", data["email"]).First(&user)
|
|
if user.Id == 0 {
|
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"message": "Invalid email or password"})
|
|
}
|
|
|
|
// Проверяем пароль
|
|
if err := bcrypt.CompareHashAndPassword(user.Password, []byte(data["password"])); err != nil {
|
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"message": "Invalid email or password"})
|
|
}
|
|
|
|
// Генерируем токен
|
|
token, err := generateToken(user)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"message": "Could not generate token"})
|
|
}
|
|
|
|
// Сохраняем токен в cookie
|
|
c.Cookie(&fiber.Cookie{
|
|
Name: "jwt",
|
|
Value: token,
|
|
Expires: time.Now().Add(time.Hour * 24),
|
|
HTTPOnly: true,
|
|
})
|
|
|
|
return c.JSON(fiber.Map{"message": "Login successful"})
|
|
}
|
|
|
|
// Получаем пользователя по токену
|
|
func User(c *fiber.Ctx) error {
|
|
cookie := c.Cookies("jwt")
|
|
token, err := jwt.ParseWithClaims(cookie, &jwt.StandardClaims{}, func(token *jwt.Token) (interface{}, error) {
|
|
return []byte(SecretKey), nil
|
|
})
|
|
|
|
if err != nil {
|
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"message": "Unauthorized"})
|
|
}
|
|
|
|
claims := token.Claims.(*jwt.StandardClaims)
|
|
if claims.ExpiresAt < time.Now().Unix() {
|
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"message": "Token expired"})
|
|
}
|
|
|
|
var user models.User
|
|
database.DB.Where("id = ?", claims.Issuer).First(&user)
|
|
|
|
return c.JSON(user)
|
|
}
|
|
|
|
// Логаут
|
|
func Logout(c *fiber.Ctx) error {
|
|
cookie := fiber.Cookie{
|
|
Name: "jwt",
|
|
Value: "",
|
|
Expires: time.Now().Add(-time.Hour),
|
|
HTTPOnly: true,
|
|
SameSite: "Strict",
|
|
}
|
|
|
|
c.Cookie(&cookie)
|
|
|
|
return c.JSON(fiber.Map{"message": "Logout success"})
|
|
}
|