package service import ( "errors" "time" "github.com/golang-jwt/jwt/v5" "golang.org/x/crypto/bcrypt" "gorm.io/gorm" "vision-tool/internal/middleware" "vision-tool/internal/model" "vision-tool/internal/repository" ) var ( ErrAdminExists = errors.New("管理员已初始化,禁止重复初始化") ErrInvalidCredentials = errors.New("用户名或密码错误") ) // AuthService 认证业务:管理员初始化 / 登录 / 用户信息。 type AuthService struct { repo *repository.UserRepository secret string expire time.Duration } func NewAuthService(repo *repository.UserRepository, secret string, expire time.Duration) *AuthService { return &AuthService{repo: repo, secret: secret, expire: expire} } // CheckAdmin 判断是否已存在管理员(方式 A:check + init)。 func (s *AuthService) CheckAdmin() (bool, error) { count, err := s.repo.Count() return count > 0, err } // InitAdmin 初始化管理员,已存在时拒绝。 func (s *AuthService) InitAdmin(username, password string) error { initialized, err := s.CheckAdmin() if err != nil { return err } if initialized { return ErrAdminExists } hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) if err != nil { return err } user := &model.User{ Username: username, PasswordHash: string(hash), Role: "admin", } return s.repo.Create(user) } // Login 校验账号密码,签发 JWT token。 func (s *AuthService) Login(username, password string) (string, error) { user, err := s.repo.FindByUsername(username) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return "", ErrInvalidCredentials } return "", err } if bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(password)) != nil { return "", ErrInvalidCredentials } claims := middleware.Claims{ UserID: user.ID, Username: user.Username, Role: user.Role, RegisteredClaims: jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate(time.Now().Add(s.expire)), IssuedAt: jwt.NewNumericDate(time.Now()), }, } return jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(s.secret)) } // Profile 按 ID 返回用户信息。 func (s *AuthService) Profile(userID uint) (*model.User, error) { return s.repo.FindByID(userID) }