feat(auth): 添加设备绑定和解绑的日志记录和缓存清理
Some checks failed
Build docker and publish / build (20.15.1) (push) Has been cancelled

在设备绑定和解绑逻辑中添加详细的日志记录,包括用户ID、设备标识符和限制检查
解绑时增加设备管理器的踢出操作,确保设备状态同步
This commit is contained in:
shanshanzhong 2025-12-02 01:38:32 -08:00
parent 6b65ffb728
commit d546ea6502
2 changed files with 65 additions and 42 deletions

View File

@ -92,7 +92,18 @@ func (l *BindDeviceLogic) createDeviceForUser(identifier, ip, userAgent string,
if limit := l.svcCtx.SessionLimit(); limit > 0 { if limit := l.svcCtx.SessionLimit(); limit > 0 {
if _, count, err := l.svcCtx.UserModel.QueryDeviceList(l.ctx, userId); err == nil { if _, count, err := l.svcCtx.UserModel.QueryDeviceList(l.ctx, userId); err == nil {
if count >= limit { if count >= limit {
l.Infow("device bind blocked by limit",
logger.Field("user_id", userId),
logger.Field("identifier", identifier),
logger.Field("count", count),
logger.Field("limit", limit))
return xerr.NewErrCodeMsg(xerr.DeviceBindLimitExceeded, "账户绑定设备数已达上限,请移除其他设备后再登录,您也可以再注册一个新账户使用,点击帮助中心查看更多详情。") return xerr.NewErrCodeMsg(xerr.DeviceBindLimitExceeded, "账户绑定设备数已达上限,请移除其他设备后再登录,您也可以再注册一个新账户使用,点击帮助中心查看更多详情。")
} else {
l.Infow("device bind limit check",
logger.Field("user_id", userId),
logger.Field("identifier", identifier),
logger.Field("count", count),
logger.Field("limit", limit))
} }
} }
} }
@ -158,7 +169,18 @@ func (l *BindDeviceLogic) rebindDeviceToNewUser(deviceInfo *user.Device, ip, use
if limit := l.svcCtx.SessionLimit(); limit > 0 { if limit := l.svcCtx.SessionLimit(); limit > 0 {
if _, count, err := l.svcCtx.UserModel.QueryDeviceList(l.ctx, newUserId); err == nil { if _, count, err := l.svcCtx.UserModel.QueryDeviceList(l.ctx, newUserId); err == nil {
if count >= limit { if count >= limit {
l.Infow("device rebind blocked by limit",
logger.Field("new_user_id", newUserId),
logger.Field("identifier", deviceInfo.Identifier),
logger.Field("count", count),
logger.Field("limit", limit))
return xerr.NewErrCodeMsg(xerr.DeviceBindLimitExceeded, "账户绑定设备数已达上限,请移除其他设备后再登录,您也可以再注册一个新账户使用,点击帮助中心查看更多详情。") return xerr.NewErrCodeMsg(xerr.DeviceBindLimitExceeded, "账户绑定设备数已达上限,请移除其他设备后再登录,您也可以再注册一个新账户使用,点击帮助中心查看更多详情。")
} else {
l.Infow("device rebind limit check",
logger.Field("new_user_id", newUserId),
logger.Field("identifier", deviceInfo.Identifier),
logger.Field("count", count),
logger.Field("limit", limit))
} }
} }
} }

View File

@ -35,24 +35,24 @@ func NewUnbindDeviceLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Unbi
func (l *UnbindDeviceLogic) UnbindDevice(req *types.UnbindDeviceRequest) error { func (l *UnbindDeviceLogic) UnbindDevice(req *types.UnbindDeviceRequest) error {
// 获取当前 token 登录的用户 // 获取当前 token 登录的用户
u, ok := l.ctx.Value(constant.CtxKeyUser).(*user.User) u, ok := l.ctx.Value(constant.CtxKeyUser).(*user.User)
if !ok { if !ok {
return errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access") return errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access")
} }
// 查询解绑设备是否存在 // 查询解绑设备是否存在
device, err := l.svcCtx.UserModel.FindOneDevice(l.ctx, req.Id) device, err := l.svcCtx.UserModel.FindOneDevice(l.ctx, req.Id)
if err != nil { if err != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DeviceNotExist), "find device") return errors.Wrapf(xerr.NewErrCode(xerr.DeviceNotExist), "find device")
} }
if device.UserId != u.Id { if device.UserId != u.Id {
return errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "device not belong to user") return errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "device not belong to user")
} }
l.Infow("开始解绑设备", l.Infow("开始解绑设备",
logger.Field("device_identifier", device.Identifier), logger.Field("device_identifier", device.Identifier),
logger.Field("user_id", u.Id)) logger.Field("user_id", u.Id))
start := time.Now() start := time.Now()
err = l.svcCtx.DB.Transaction(func(tx *gorm.DB) error { err = l.svcCtx.DB.Transaction(func(tx *gorm.DB) error {
// 1. 查询设备记录 // 1. 查询设备记录
var device user.Device var device user.Device
err = tx.Model(&device).Where("id = ?", req.Id).First(&device).Error err = tx.Model(&device).Where("id = ?", req.Id).First(&device).Error
@ -83,13 +83,13 @@ func (l *UnbindDeviceLogic) UnbindDevice(req *types.UnbindDeviceRequest) error {
} }
// 3.2 记录注册日志 // 3.2 记录注册日志
registerLog := log.Register{ registerLog := log.Register{
AuthMethod: "device", AuthMethod: "device",
Identifier: device.Identifier, Identifier: device.Identifier,
RegisterIP: device.Ip, RegisterIP: device.Ip,
UserAgent: device.UserAgent, UserAgent: device.UserAgent,
Timestamp: time.Now().UnixMilli(), Timestamp: time.Now().UnixMilli(),
} }
content, _ := registerLog.Marshal() content, _ := registerLog.Marshal()
if err := tx.Create(&log.SystemLog{ if err := tx.Create(&log.SystemLog{
Type: log.TypeRegister.Uint8(), Type: log.TypeRegister.Uint8(),
@ -129,28 +129,29 @@ func (l *UnbindDeviceLogic) UnbindDevice(req *types.UnbindDeviceRequest) error {
} }
// 6. 清理缓存 // 6. 清理缓存
l.Infow("设备解绑并迁移成功", l.Infow("设备解绑并迁移成功",
logger.Field("device_identifier", device.Identifier), logger.Field("device_identifier", device.Identifier),
logger.Field("old_user_id", device.UserId), logger.Field("old_user_id", device.UserId),
logger.Field("new_user_id", newUser.Id)) logger.Field("new_user_id", newUser.Id))
return nil return nil
}) })
if err != nil { if err != nil {
return err return err
} }
duration := time.Since(start) duration := time.Since(start)
identifier := device.Identifier identifier := device.Identifier
ctx, cancel := context.WithTimeout(l.ctx, 2*time.Second) ctx, cancel := context.WithTimeout(l.ctx, 2*time.Second)
defer cancel() defer cancel()
deviceCacheKey := fmt.Sprintf("%v:%v", config.DeviceCacheKeyKey, identifier) deviceCacheKey := fmt.Sprintf("%v:%v", config.DeviceCacheKeyKey, identifier)
if sessionId, rerr := l.svcCtx.Redis.Get(ctx, deviceCacheKey).Result(); rerr == nil && sessionId != "" { if sessionId, rerr := l.svcCtx.Redis.Get(ctx, deviceCacheKey).Result(); rerr == nil && sessionId != "" {
_ = l.svcCtx.Redis.Del(ctx, deviceCacheKey).Err() _ = l.svcCtx.Redis.Del(ctx, deviceCacheKey).Err()
sessionIdCacheKey := fmt.Sprintf("%v:%v", config.SessionIdKey, sessionId) sessionIdCacheKey := fmt.Sprintf("%v:%v", config.SessionIdKey, sessionId)
_ = l.svcCtx.Redis.Del(ctx, sessionIdCacheKey).Err() _ = l.svcCtx.Redis.Del(ctx, sessionIdCacheKey).Err()
} }
l.Infow("设备解绑完成", l.svcCtx.DeviceManager.KickDevice(u.Id, identifier)
logger.Field("device_identifier", identifier), l.Infow("设备解绑完成",
logger.Field("elapsed_ms", duration.Milliseconds())) logger.Field("device_identifier", identifier),
return nil logger.Field("elapsed_ms", duration.Milliseconds()))
return nil
} }