package user import ( "context" "encoding/json" "errors" "time" "perms-system-server/internal/consts" "perms-system-server/internal/loaders" authHelper "perms-system-server/internal/logic/auth" "perms-system-server/internal/middleware" userModel "perms-system-server/internal/model/user" "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/logx" "golang.org/x/crypto/bcrypt" ) type ResetPasswordLogic struct { logx.Logger ctx context.Context svcCtx *svc.ServiceContext } func NewResetPasswordLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ResetPasswordLogic { return &ResetPasswordLogic{ Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx, } } func (l *ResetPasswordLogic) ResetPassword(req *types.ResetPasswordReq) (resp *types.ResetPasswordResp, err error) { productCode := middleware.GetProductCode(l.ctx) if err := authHelper.RequireProductAdminFor(l.ctx, productCode); err != nil { return nil, err } target, err := l.svcCtx.SysUserModel.FindOne(l.ctx, req.UserId) if err != nil { return nil, response.ErrNotFound("用户不存在") } if target.IsSuperAdmin == consts.IsSuperAdminYes { return nil, response.ErrForbidden("不能重置超级管理员的密码") } if err := authHelper.CheckManageAccess(l.ctx, l.svcCtx, req.UserId, productCode); err != nil { return nil, err } plainPassword, err := util.GenerateStrongInitialPassword(16) if err != nil { return nil, err } hashedPwd, err := bcrypt.GenerateFromPassword([]byte(plainPassword), bcrypt.DefaultCost) if err != nil { return nil, err } if err := l.svcCtx.SysUserModel.UpdatePassword(l.ctx, target.Id, target.Username, string(hashedPwd), consts.MustChangePasswordYes, target.UpdateTime); err != nil { if errors.Is(err, userModel.ErrUpdateConflict) { return nil, response.ErrConflict("数据已被其他操作修改,请刷新后重试") } return nil, err } cleanCtx, cancel := loaders.DetachCacheCleanCtx(l.ctx) defer cancel() l.svcCtx.UserDetailsLoader.Clean(cleanCtx, target.Id) ticket, err := util.GenerateRandomHex(32) if err != nil { l.Errorf("resetPassword: generate ticket failed: %v", err) return nil, response.NewCodeError(503, "凭证服务暂时不可用,请稍后重试") } payload := userCredentialsPayload{Username: target.Username, Password: plainPassword} buf, _ := json.Marshal(&payload) key := userCredentialsKeyPrefix + ticket if err := l.svcCtx.Redis.SetexCtx(l.ctx, key, string(buf), int(userCredentialsTTL/time.Second)); err != nil { l.Errorf("resetPassword: redis setex failed: %v", err) return nil, response.NewCodeError(503, "凭证服务暂时不可用,请稍后重试") } return &types.ResetPasswordResp{ CredentialsTicket: ticket, CredentialsExpiresAt: time.Now().Unix() + int64(userCredentialsTTL/time.Second), }, nil }