|
|
@@ -0,0 +1,97 @@
|
|
|
+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
|
|
|
+}
|