package service import ( "encoding/json" "errors" "log" "os" "path/filepath" "strings" "time" "x-agents/server/internal/model" "x-agents/server/internal/repository" "github.com/golang-jwt/jwt/v5" "github.com/google/uuid" "golang.org/x/crypto/bcrypt" ) var ( ErrInvalidCredentials = errors.New("invalid credentials") ErrUserNotFound = errors.New("user not found") ) type AuthService struct { jwtSecret string userRepo *repository.UserRepository } func NewAuthService(jwtSecret string, userRepo *repository.UserRepository) *AuthService { return &AuthService{ jwtSecret: jwtSecret, userRepo: userRepo, } } type LoginRequest struct { Username string `json:"username" binding:"required"` Password string `json:"password" binding:"required"` } type LoginResponse struct { Token string `json:"token"` User *model.User `json:"user"` } func (s *AuthService) Login(req LoginRequest) (*LoginResponse, error) { // 查找用户 user, err := s.userRepo.FindByUsername(req.Username) if err != nil { return nil, ErrInvalidCredentials } // 验证密码 if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.Password)); err != nil { return nil, ErrInvalidCredentials } // 生成Token token, err := s.generateToken(user) if err != nil { return nil, err } return &LoginResponse{ Token: token, User: user, }, nil } func (s *AuthService) generateToken(user *model.User) (string, error) { claims := jwt.MapClaims{ "sub": user.ID, "username": user.Username, "role": user.RoleID, "exp": time.Now().Add(time.Hour * 24 * 7).Unix(), // 7天有效期 "iat": time.Now().Unix(), "expires_at": time.Now().Add(time.Hour * 24 * 7).Format(time.RFC3339), } token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) return token.SignedString([]byte(s.jwtSecret)) } func (s *AuthService) ValidateToken(tokenString string) (jwt.MapClaims, error) { token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, errors.New("unexpected signing method") } return []byte(s.jwtSecret), nil }) if err != nil { return nil, err } if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { return claims, nil } return nil, errors.New("invalid token") } func (s *AuthService) Register(username, password, email string) (*model.User, error) { // 检查用户是否已存在 _, err := s.userRepo.FindByUsername(username) if err == nil { return nil, errors.New("user already exists") } // 加密密码 hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) if err != nil { return nil, err } // 创建用户 user := &model.User{ ID: uuid.New().String(), Username: username, Password: string(hashedPassword), Email: email, RoleID: "user", IsActive: true, } // 如果没有用户,创建默认管理员角色 role, err := s.userRepo.FindRoleByID(user.RoleID) if err != nil { // 创建默认角色 perms, _ := json.Marshal([]int{int(model.PermissionRead), int(model.PermissionWrite)}) role = &model.Role{ ID: "user", Name: "user", Permissions: string(perms), } s.userRepo.CreateRole(role) user.Role = role } if err := s.userRepo.Create(user); err != nil { return nil, err } // 创建用户工作空间目录 if err := s.createUserWorkspace(username); err != nil { // 工作空间创建失败不影响注册成功,仅记录日志 println("Warning: failed to create user workspace:", err.Error()) } return user, nil } // createUserWorkspace 创建用户工作空间目录 func (s *AuthService) createUserWorkspace(username string) error { // 获取当前可执行文件所在目录 execPath, err := os.Getwd() if err != nil { return err } // 尝试多种方式获取项目根目录 projectRoot := execPath // 方式1: 如果当前目录名为 server,向上找一级 baseName := filepath.Base(execPath) // 处理 Windows 和 Unix 风格路径 if baseName == "server" || strings.HasSuffix(execPath, "/server") || strings.HasSuffix(execPath, "\\server") { projectRoot = filepath.Dir(execPath) } // 方式2: 尝试向上查找包含 .git 或 package.json 的目录 if _, err := os.Stat(filepath.Join(projectRoot, ".git")); os.IsNotExist(err) { // 继续向上查找 for i := 0; i < 3; i++ { parent := filepath.Dir(projectRoot) if parent == projectRoot { break } if _, err := os.Stat(filepath.Join(parent, ".git")); err == nil { projectRoot = parent break } projectRoot = parent } } log.Printf("[Workspace] Creating workspace at: %s", filepath.Join(projectRoot, "account", username)) // 创建 account 目录和用户目录 workspacePath := filepath.Join(projectRoot, "account", username) if err := os.MkdirAll(workspacePath, 0755); err != nil { return err } // 创建子目录: skills(技能), scripts(脚本), sandbox(沙盒), files(文件), temp(临时) subDirs := []string{"skills", "scripts", "sandbox", "files", "temp"} for _, dir := range subDirs { if err := os.MkdirAll(filepath.Join(workspacePath, dir), 0755); err != nil { return err } } return nil } // GetUserByID 根据ID获取用户 func (s *AuthService) GetUserByID(id string) (*model.User, error) { return s.userRepo.FindByID(id) } // GetAllUsers 获取所有用户 func (s *AuthService) GetAllUsers() ([]model.User, error) { return s.userRepo.FindAll() }