auth.go 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. package service
  2. import (
  3. "context"
  4. "dsbqj-admin/model/mongo/admin"
  5. "dsbqj-admin/pkg/util"
  6. "errors"
  7. "os"
  8. "strings"
  9. "time"
  10. "github.com/kamva/mgm/v3"
  11. "go.mongodb.org/mongo-driver/bson"
  12. "golang.org/x/crypto/bcrypt"
  13. )
  14. const defaultAdminUsername = "admin"
  15. const defaultAdminPassword = "admin123"
  16. type AdminClaims struct {
  17. Username string `json:"username"`
  18. ExpiresAt int64 `json:"expires_at"`
  19. }
  20. type LoginService struct {
  21. Username string `json:"username" binding:"required"`
  22. Password string `json:"password" binding:"required"`
  23. }
  24. type ChangePasswordService struct {
  25. Username string `json:"-"`
  26. OldPassword string `json:"oldPassword" binding:"required"`
  27. NewPassword string `json:"newPassword" binding:"required,min=6"`
  28. }
  29. func EnsureDefaultAdmin() error {
  30. coll := mgm.Coll(&admin.Admin{})
  31. count, err := coll.CountDocuments(context.Background(), bson.M{})
  32. if err != nil || count > 0 {
  33. return err
  34. }
  35. username := strings.TrimSpace(os.Getenv("ADMIN_USERNAME"))
  36. password := os.Getenv("ADMIN_PASSWORD")
  37. if username == "" {
  38. username = defaultAdminUsername
  39. }
  40. if password == "" {
  41. password = defaultAdminPassword
  42. }
  43. hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
  44. if err != nil {
  45. return err
  46. }
  47. return coll.Create(&admin.Admin{Username: username, PasswordHash: string(hash)})
  48. }
  49. func (s *LoginService) Login() (map[string]interface{}, error) {
  50. var account admin.Admin
  51. err := mgm.Coll(&account).First(bson.M{"username": strings.TrimSpace(s.Username)}, &account)
  52. if err != nil || bcrypt.CompareHashAndPassword([]byte(account.PasswordHash), []byte(s.Password)) != nil {
  53. return nil, errors.New("invalid username or password")
  54. }
  55. claims := AdminClaims{Username: account.Username, ExpiresAt: time.Now().Add(24 * time.Hour).Unix()}
  56. token := util.GenerateToken(claims, util.AdminTokenSecret())
  57. if token == "" {
  58. return nil, errors.New("failed to generate login token")
  59. }
  60. return map[string]interface{}{
  61. "token": token, "username": account.Username, "role": "admin",
  62. "roleId": "admin", "permissions": []string{"*"},
  63. }, nil
  64. }
  65. func (s *ChangePasswordService) Change() error {
  66. if len(s.NewPassword) < 6 {
  67. return errors.New("new password must contain at least 6 characters")
  68. }
  69. if s.OldPassword == s.NewPassword {
  70. return errors.New("new password must differ from old password")
  71. }
  72. var account admin.Admin
  73. coll := mgm.Coll(&account)
  74. if err := coll.First(bson.M{"username": s.Username}, &account); err != nil {
  75. return errors.New("account not found")
  76. }
  77. if bcrypt.CompareHashAndPassword([]byte(account.PasswordHash), []byte(s.OldPassword)) != nil {
  78. return errors.New("old password is incorrect")
  79. }
  80. hash, err := bcrypt.GenerateFromPassword([]byte(s.NewPassword), bcrypt.DefaultCost)
  81. if err != nil {
  82. return err
  83. }
  84. _, err = coll.UpdateOne(context.Background(), bson.M{"_id": account.ID}, bson.M{
  85. "$set": bson.M{"password_hash": string(hash), "updated_at": time.Now()},
  86. })
  87. return err
  88. }