2025-10-07 20:59:46 +00:00
|
|
|
package service
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"errors"
|
|
|
|
|
"os"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"github.com/golang-jwt/jwt/v5"
|
|
|
|
|
"golang.org/x/crypto/bcrypt"
|
|
|
|
|
|
|
|
|
|
"github.com/mhsanaei/3x-ui/v2/database"
|
|
|
|
|
"github.com/mhsanaei/3x-ui/v2/database/model"
|
|
|
|
|
"gorm.io/gorm"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type AuthService struct {
|
|
|
|
|
DB *gorm.DB
|
|
|
|
|
JWTSecret []byte
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewAuthService() *AuthService {
|
|
|
|
|
secret := os.Getenv("JWT_SECRET")
|
|
|
|
|
if secret == "" {
|
|
|
|
|
secret = "dev-secret-change-me"
|
|
|
|
|
}
|
|
|
|
|
return &AuthService{
|
|
|
|
|
DB: database.GetDB(),
|
|
|
|
|
JWTSecret: []byte(secret),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Регистрация (используем существующую модель: Username + PasswordHash + Role)
|
|
|
|
|
func (s *AuthService) Register(username, rawPassword, role string) error {
|
|
|
|
|
if role == "" {
|
|
|
|
|
role = "reader"
|
|
|
|
|
}
|
|
|
|
|
hash, err := bcrypt.GenerateFromPassword([]byte(rawPassword), 12)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
u := &model.User{
|
|
|
|
|
Username: username,
|
|
|
|
|
PasswordHash: string(hash),
|
|
|
|
|
Role: role,
|
|
|
|
|
}
|
|
|
|
|
return s.DB.Create(u).Error
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *AuthService) Login(username, rawPassword string) (string, *model.User, error) {
|
|
|
|
|
var u model.User
|
|
|
|
|
if err := s.DB.Where("username = ?", username).First(&u).Error; err != nil {
|
|
|
|
|
if database.IsNotFound(err) {
|
|
|
|
|
return "", nil, errors.New("user not found")
|
|
|
|
|
}
|
|
|
|
|
return "", nil, err
|
|
|
|
|
}
|
|
|
|
|
if err := bcrypt.CompareHashAndPassword([]byte(u.PasswordHash), []byte(rawPassword)); err != nil {
|
|
|
|
|
return "", nil, errors.New("invalid password")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
claims := jwt.MapClaims{
|
|
|
|
|
"id": u.Id,
|
|
|
|
|
"username": u.Username,
|
|
|
|
|
"role": u.Role,
|
|
|
|
|
"exp": time.Now().Add(72 * time.Hour).Unix(),
|
|
|
|
|
}
|
|
|
|
|
tok, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString(s.JWTSecret)
|
|
|
|
|
return tok, &u, err
|
|
|
|
|
}
|