功能:完善登录安全与客服手动下单
This commit is contained in:
@@ -2,6 +2,7 @@ package service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"affiliate_dash/internal/model"
|
||||
"affiliate_dash/internal/pkg/jwt"
|
||||
@@ -54,6 +55,37 @@ func (s *AuthService) GetProfile(userID uint) (*model.User, error) {
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
// ChangePassword only changes the current account after its existing password is verified.
|
||||
func (s *AuthService) ChangePassword(userID uint, currentPassword, newPassword string) error {
|
||||
if userID == 0 {
|
||||
return errors.New("无效的用户身份")
|
||||
}
|
||||
if len(newPassword) < 8 {
|
||||
return errors.New("新密码至少 8 位")
|
||||
}
|
||||
if strings.TrimSpace(newPassword) == "" {
|
||||
return errors.New("新密码不能为空")
|
||||
}
|
||||
var user model.User
|
||||
if err := s.db.First(&user, userID).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return errors.New("用户不存在")
|
||||
}
|
||||
return err
|
||||
}
|
||||
if err := bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(currentPassword)); err != nil {
|
||||
return errors.New("当前密码错误")
|
||||
}
|
||||
if err := bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(newPassword)); err == nil {
|
||||
return errors.New("新密码不能与当前密码相同")
|
||||
}
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.db.Model(&user).Update("password_hash", string(hash)).Error
|
||||
}
|
||||
|
||||
func (s *AuthService) EnsureAdmin() error {
|
||||
var count int64
|
||||
s.db.Model(&model.User{}).Where("role = ?", model.RoleAdmin).Count(&count)
|
||||
|
||||
@@ -6,6 +6,8 @@ import (
|
||||
"testing"
|
||||
|
||||
"affiliate_dash/internal/model"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
func TestCreateAPIClientEnforcesPerMerchantLimit(t *testing.T) {
|
||||
@@ -174,3 +176,29 @@ func TestMemberCanBeUpdatedOrRemovedWithoutDeletingAccount(t *testing.T) {
|
||||
t.Fatalf("member relationship should be removed, count=%d err=%v", count, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthServiceChangePasswordVerifiesCurrentPassword(t *testing.T) {
|
||||
db := newServiceTestDB(t)
|
||||
tenant := NewTenantService(db)
|
||||
auth := NewAuthService(db, nil, tenant)
|
||||
user, err := NewUserService(db, tenant).Create("password-owner", "old-password", "密码管理员", model.RoleAdmin, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("create user: %v", err)
|
||||
}
|
||||
if err := auth.ChangePassword(user.ID, "wrong-password", "new-password"); err == nil {
|
||||
t.Fatal("expected current password validation error")
|
||||
}
|
||||
if err := auth.ChangePassword(user.ID, "old-password", "new-password"); err != nil {
|
||||
t.Fatalf("change password: %v", err)
|
||||
}
|
||||
var saved model.User
|
||||
if err := db.First(&saved, user.ID).Error; err != nil {
|
||||
t.Fatalf("load updated user: %v", err)
|
||||
}
|
||||
if err := bcrypt.CompareHashAndPassword([]byte(saved.PasswordHash), []byte("new-password")); err != nil {
|
||||
t.Fatalf("new password should match: %v", err)
|
||||
}
|
||||
if err := bcrypt.CompareHashAndPassword([]byte(saved.PasswordHash), []byte("old-password")); err == nil {
|
||||
t.Fatal("old password should no longer match")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user