package service import ( "context" "dsbqj-admin/model/mongo/admin" "dsbqj-admin/pkg/util" "errors" "os" "strings" "time" "github.com/kamva/mgm/v3" "go.mongodb.org/mongo-driver/bson" "golang.org/x/crypto/bcrypt" ) const defaultAdminUsername = "admin" const defaultAdminPassword = "admin123" type AdminClaims struct { Username string `json:"username"` ExpiresAt int64 `json:"expires_at"` } type LoginService struct { Username string `json:"username" binding:"required"` Password string `json:"password" binding:"required"` } type ChangePasswordService struct { Username string `json:"-"` OldPassword string `json:"oldPassword" binding:"required"` NewPassword string `json:"newPassword" binding:"required,min=6"` } func EnsureDefaultAdmin() error { coll := mgm.Coll(&admin.Admin{}) count, err := coll.CountDocuments(context.Background(), bson.M{}) if err != nil || count > 0 { return err } username := strings.TrimSpace(os.Getenv("ADMIN_USERNAME")) password := os.Getenv("ADMIN_PASSWORD") if username == "" { username = defaultAdminUsername } if password == "" { password = defaultAdminPassword } hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) if err != nil { return err } return coll.Create(&admin.Admin{Username: username, PasswordHash: string(hash)}) } func (s *LoginService) Login() (map[string]interface{}, error) { var account admin.Admin err := mgm.Coll(&account).First(bson.M{"username": strings.TrimSpace(s.Username)}, &account) if err != nil || bcrypt.CompareHashAndPassword([]byte(account.PasswordHash), []byte(s.Password)) != nil { return nil, errors.New("invalid username or password") } claims := AdminClaims{Username: account.Username, ExpiresAt: time.Now().Add(24 * time.Hour).Unix()} token := util.GenerateToken(claims, util.AdminTokenSecret()) if token == "" { return nil, errors.New("failed to generate login token") } return map[string]interface{}{ "token": token, "username": account.Username, "role": "admin", "roleId": "admin", "permissions": []string{"*"}, }, nil } func (s *ChangePasswordService) Change() error { if len(s.NewPassword) < 6 { return errors.New("new password must contain at least 6 characters") } if s.OldPassword == s.NewPassword { return errors.New("new password must differ from old password") } var account admin.Admin coll := mgm.Coll(&account) if err := coll.First(bson.M{"username": s.Username}, &account); err != nil { return errors.New("account not found") } if bcrypt.CompareHashAndPassword([]byte(account.PasswordHash), []byte(s.OldPassword)) != nil { return errors.New("old password is incorrect") } hash, err := bcrypt.GenerateFromPassword([]byte(s.NewPassword), bcrypt.DefaultCost) if err != nil { return err } _, err = coll.UpdateOne(context.Background(), bson.M{"_id": account.ID}, bson.M{ "$set": bson.M{"password_hash": string(hash), "updated_at": time.Now()}, }) return err }