package auth import ( "context" "fmt" "perms-system-server/internal/consts" "perms-system-server/internal/middleware" "perms-system-server/internal/response" "perms-system-server/internal/svc" "perms-system-server/internal/types" "perms-system-server/internal/util" "github.com/zeromicro/go-zero/core/limit" "github.com/zeromicro/go-zero/core/logx" "golang.org/x/crypto/bcrypt" ) type ChangePasswordLogic struct { logx.Logger ctx context.Context svcCtx *svc.ServiceContext } func NewChangePasswordLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ChangePasswordLogic { return &ChangePasswordLogic{ Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx, } } // ChangePassword 修改密码。已登录用户验证原密码后设置新密码,同时递增 tokenVersion 使所有已签发令牌失效,强制重新登录。 func (l *ChangePasswordLogic) ChangePassword(req *types.ChangePasswordReq) error { if msg := util.ValidatePassword(req.NewPassword); msg != "" { return response.ErrBadRequest(msg) } userId := middleware.GetUserId(l.ctx) if l.svcCtx.TokenOpLimiter != nil { code, _ := l.svcCtx.TokenOpLimiter.Take(fmt.Sprintf("chpwd:%d", userId)) if code == limit.OverQuota { return response.ErrTooManyRequests("操作过于频繁,请稍后再试") } } user, err := l.svcCtx.SysUserModel.FindOne(l.ctx, userId) if err != nil { return response.ErrNotFound("用户不存在") } if user.Status != consts.StatusEnabled { return response.ErrForbidden("账号已被冻结") } if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.OldPassword)); err != nil { logx.WithContext(l.ctx).Infof("change-password old-password mismatch userId=%d", userId) return response.ErrBadRequest("原密码错误") } if req.OldPassword == req.NewPassword { return response.ErrBadRequest("新密码不能与原密码相同") } hashed, err := bcrypt.GenerateFromPassword([]byte(req.NewPassword), bcrypt.DefaultCost) if err != nil { return err } if err := l.svcCtx.SysUserModel.UpdatePassword(l.ctx, userId, string(hashed), consts.MustChangePasswordNo); err != nil { return err } l.svcCtx.UserDetailsLoader.Clean(l.ctx, userId) return nil }