3.7 KiB
3.7 KiB
设备移出和邀请码优化 - 共识文档(更新版)
需求概述
修复两个 Bug:
- Bug 1:设备B绑定邮箱后被从设备A移除,设备B没有被踢下线
- Bug 2:输入不存在的邀请码时,提示信息不友好
Bug 1:设备移出后未自动退出
根本原因
设备B绑定邮箱(迁移到邮箱用户)时:
- ✅ 数据库更新了设备的
UserId - ❌
DeviceManager内存中设备B的 WebSocket 连接仍在原用户名下 - ❌ Redis 缓存中设备B的 session 未被清理
解绑设备B时,KickDevice(用户1, "device-b") 在用户1的设备列表中找不到 device-b(因为连接还在原用户名下)。
修复方案
文件1:bindEmailWithVerificationLogic.go
在设备迁移后,踢出旧连接并清理缓存:
// 第 139-158 行之后添加
for _, device := range devices {
device.UserId = emailUserId
err = l.svcCtx.UserModel.UpdateDevice(l.ctx, device)
// ...existing code...
// 新增:踢出旧连接并清理缓存
l.svcCtx.DeviceManager.KickDevice(u.Id, device.Identifier)
deviceCacheKey := fmt.Sprintf("%v:%v", config.DeviceCacheKeyKey, device.Identifier)
if sessionId, _ := l.svcCtx.Redis.Get(l.ctx, deviceCacheKey).Result(); sessionId != "" {
sessionIdCacheKey := fmt.Sprintf("%v:%v", config.SessionIdKey, sessionId)
_ = l.svcCtx.Redis.Del(l.ctx, deviceCacheKey).Err()
_ = l.svcCtx.Redis.Del(l.ctx, sessionIdCacheKey).Err()
}
}
文件2:unbindDeviceLogic.go(防御性修复)
补充 user_sessions 清理逻辑,与 deleteUserDeviceLogic.go 保持一致:
// 第 118-122 行,补充 sessionsKey 清理
if sessionId, rerr := l.svcCtx.Redis.Get(ctx, deviceCacheKey).Result(); rerr == nil && sessionId != "" {
_ = l.svcCtx.Redis.Del(ctx, deviceCacheKey).Err()
sessionIdCacheKey := fmt.Sprintf("%v:%v", config.SessionIdKey, sessionId)
_ = l.svcCtx.Redis.Del(ctx, sessionIdCacheKey).Err()
// 新增:清理 user_sessions
sessionsKey := fmt.Sprintf("%s%v", config.UserSessionsKeyPrefix, device.UserId)
_ = l.svcCtx.Redis.ZRem(ctx, sessionsKey, sessionId).Err()
}
Bug 2:邀请码错误提示不友好
根本原因
bindInviteCodeLogic.go 中未区分"邀请码不存在"和"数据库错误"。
修复方案
// 第 44-47 行修改为
referrer, err := l.svcCtx.UserModel.FindOneByReferCode(l.ctx, req.InviteCode)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return errors.Wrapf(xerr.NewErrCodeMsg(xerr.InviteCodeError, "无邀请码"), "invite code not found")
}
logger.WithContext(l.ctx).Error(err)
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query referrer failed: %v", err.Error())
}
涉及文件汇总
| 文件 | 修改类型 | 优先级 |
|---|---|---|
internal/logic/public/user/bindEmailWithVerificationLogic.go |
核心修复 | 高 |
internal/logic/public/user/unbindDeviceLogic.go |
防御性修复 | 中 |
internal/logic/public/user/bindInviteCodeLogic.go |
Bug 修复 | 中 |
验收标准
Bug 1 验收
- 设备B绑定邮箱后,设备B的旧 Token 失效
- 设备B绑定邮箱后,设备B的 WebSocket 连接被断开
- 在设备A上移除设备B后,设备B立即被踢下线
- 设备B无法继续使用旧 Token 调用 API
Bug 2 验收
- 输入不存在的邀请码时,返回错误码 20009
- 错误消息显示"无邀请码"
验证计划
- 编译验证:
go build ./... - 手动测试:
- 设备B绑定邮箱 → 检查是否被踢下线
- 设备A移除设备B → 检查设备B是否被踢下线
- 输入无效邀请码 → 检查错误提示