resetPasswordLogic.go 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. package user
  2. import (
  3. "context"
  4. "encoding/json"
  5. "errors"
  6. "time"
  7. "perms-system-server/internal/consts"
  8. "perms-system-server/internal/loaders"
  9. authHelper "perms-system-server/internal/logic/auth"
  10. "perms-system-server/internal/middleware"
  11. userModel "perms-system-server/internal/model/user"
  12. "perms-system-server/internal/response"
  13. "perms-system-server/internal/svc"
  14. "perms-system-server/internal/types"
  15. "perms-system-server/internal/util"
  16. "github.com/zeromicro/go-zero/core/logx"
  17. "golang.org/x/crypto/bcrypt"
  18. )
  19. type ResetPasswordLogic struct {
  20. logx.Logger
  21. ctx context.Context
  22. svcCtx *svc.ServiceContext
  23. }
  24. func NewResetPasswordLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ResetPasswordLogic {
  25. return &ResetPasswordLogic{
  26. Logger: logx.WithContext(ctx),
  27. ctx: ctx,
  28. svcCtx: svcCtx,
  29. }
  30. }
  31. func (l *ResetPasswordLogic) ResetPassword(req *types.ResetPasswordReq) (resp *types.ResetPasswordResp, err error) {
  32. productCode := middleware.GetProductCode(l.ctx)
  33. if err := authHelper.RequireProductAdminFor(l.ctx, productCode); err != nil {
  34. return nil, err
  35. }
  36. target, err := l.svcCtx.SysUserModel.FindOne(l.ctx, req.UserId)
  37. if err != nil {
  38. return nil, response.ErrNotFound("用户不存在")
  39. }
  40. if target.IsSuperAdmin == consts.IsSuperAdminYes {
  41. return nil, response.ErrForbidden("不能重置超级管理员的密码")
  42. }
  43. if err := authHelper.CheckManageAccess(l.ctx, l.svcCtx, req.UserId, productCode); err != nil {
  44. return nil, err
  45. }
  46. plainPassword, err := util.GenerateStrongInitialPassword(16)
  47. if err != nil {
  48. return nil, err
  49. }
  50. hashedPwd, err := bcrypt.GenerateFromPassword([]byte(plainPassword), bcrypt.DefaultCost)
  51. if err != nil {
  52. return nil, err
  53. }
  54. if err := l.svcCtx.SysUserModel.UpdatePassword(l.ctx, target.Id, target.Username, string(hashedPwd), consts.MustChangePasswordYes, target.UpdateTime); err != nil {
  55. if errors.Is(err, userModel.ErrUpdateConflict) {
  56. return nil, response.ErrConflict("数据已被其他操作修改,请刷新后重试")
  57. }
  58. return nil, err
  59. }
  60. cleanCtx, cancel := loaders.DetachCacheCleanCtx(l.ctx)
  61. defer cancel()
  62. l.svcCtx.UserDetailsLoader.Clean(cleanCtx, target.Id)
  63. ticket, err := util.GenerateRandomHex(32)
  64. if err != nil {
  65. l.Errorf("resetPassword: generate ticket failed: %v", err)
  66. return nil, response.NewCodeError(503, "凭证服务暂时不可用,请稍后重试")
  67. }
  68. payload := userCredentialsPayload{Username: target.Username, Password: plainPassword}
  69. buf, _ := json.Marshal(&payload)
  70. key := userCredentialsKeyPrefix + ticket
  71. if err := l.svcCtx.Redis.SetexCtx(l.ctx, key, string(buf), int(userCredentialsTTL/time.Second)); err != nil {
  72. l.Errorf("resetPassword: redis setex failed: %v", err)
  73. return nil, response.NewCodeError(503, "凭证服务暂时不可用,请稍后重试")
  74. }
  75. return &types.ResetPasswordResp{
  76. CredentialsTicket: ticket,
  77. CredentialsExpiresAt: time.Now().Unix() + int64(userCredentialsTTL/time.Second),
  78. }, nil
  79. }