updateUserStatusLogic.go 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. package user
  2. import (
  3. "context"
  4. "errors"
  5. "perms-system-server/internal/consts"
  6. authHelper "perms-system-server/internal/logic/auth"
  7. "perms-system-server/internal/middleware"
  8. userModel "perms-system-server/internal/model/user"
  9. "perms-system-server/internal/response"
  10. "perms-system-server/internal/svc"
  11. "perms-system-server/internal/types"
  12. "github.com/zeromicro/go-zero/core/logx"
  13. )
  14. type UpdateUserStatusLogic struct {
  15. logx.Logger
  16. ctx context.Context
  17. svcCtx *svc.ServiceContext
  18. }
  19. func NewUpdateUserStatusLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateUserStatusLogic {
  20. return &UpdateUserStatusLogic{
  21. Logger: logx.WithContext(ctx),
  22. ctx: ctx,
  23. svcCtx: svcCtx,
  24. }
  25. }
  26. // UpdateUserStatus 冻结/解冻用户。修改用户启用状态并递增 tokenVersion 使其令牌失效。不能修改自身或超管状态。
  27. // 若状态未实际变更则不做任何写操作,避免不必要的 tokenVersion 递增踢用户下线。
  28. func (l *UpdateUserStatusLogic) UpdateUserStatus(req *types.UpdateUserStatusReq) error {
  29. if req.Status != consts.StatusEnabled && req.Status != consts.StatusDisabled {
  30. return response.ErrBadRequest("状态值无效,仅支持 1(启用) 和 2(冻结)")
  31. }
  32. callerId := middleware.GetUserId(l.ctx)
  33. // ValidateStatusChange 内部已经 FindOne(targetUserId),结果透传给 CheckManageAccess 和
  34. // 下方的 status 对比,避免单次请求内重复 3 次 FindOne(见审计 M-5)。
  35. user, err := authHelper.ValidateStatusChange(l.ctx, l.svcCtx, callerId, req.Id)
  36. if err != nil {
  37. return err
  38. }
  39. productCode := middleware.GetProductCode(l.ctx)
  40. if err := authHelper.CheckManageAccess(l.ctx, l.svcCtx, req.Id, productCode, authHelper.WithPrefetchedTarget(user)); err != nil {
  41. return err
  42. }
  43. if user.Status == req.Status {
  44. return nil
  45. }
  46. // 审计 L-N4:把 FindOne 拿到的 UpdateTime 作为乐观锁,避免两个 admin 并发冻结/解冻时
  47. // last-write-wins,被连续 +2 tokenVersion、刚解冻又被踢下线等现象。
  48. if err := l.svcCtx.SysUserModel.UpdateStatus(l.ctx, req.Id, req.Status, user.UpdateTime); err != nil {
  49. if errors.Is(err, userModel.ErrUpdateConflict) {
  50. return response.ErrConflict("数据已被其他操作修改,请刷新后重试")
  51. }
  52. return err
  53. }
  54. l.svcCtx.UserDetailsLoader.Clean(l.ctx, req.Id)
  55. return nil
  56. }