hi-server/internal/logic/public/user/unbindDeviceLogic.go
shanshanzhong 00255a7118
Some checks failed
Build docker and publish / build (20.15.1) (push) Has been cancelled
feat: 新增多密码验证支持及架构文档
refactor: 重构用户模型和密码验证逻辑
feat(epay): 添加支付类型支持
docs: 添加安装和配置指南文档
fix: 修复优惠券过期检查逻辑
perf: 优化设备解绑缓存清理流程
test: 添加密码验证测试用例
chore: 更新依赖版本
2025-10-27 18:54:07 -07:00

140 lines
4.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package user
import (
"context"
"fmt"
"github.com/perfect-panel/server/internal/config"
"github.com/perfect-panel/server/internal/model/user"
"github.com/perfect-panel/server/internal/svc"
"github.com/perfect-panel/server/internal/types"
"github.com/perfect-panel/server/pkg/constant"
"github.com/perfect-panel/server/pkg/logger"
"github.com/perfect-panel/server/pkg/xerr"
"github.com/pkg/errors"
"gorm.io/gorm"
)
type UnbindDeviceLogic struct {
logger.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
// Unbind Device
func NewUnbindDeviceLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UnbindDeviceLogic {
return &UnbindDeviceLogic{
Logger: logger.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *UnbindDeviceLogic) UnbindDevice(req *types.UnbindDeviceRequest) error {
userInfo := l.ctx.Value(constant.CtxKeyUser).(*user.User)
device, err := l.svcCtx.UserModel.FindOneDevice(l.ctx, req.Id)
if err != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DeviceNotExist), "find device")
}
if device.UserId != userInfo.Id {
return errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "device not belong to user")
}
// 保存设备信息用于后续缓存清理
deviceIdentifier := device.Identifier
userId := device.UserId
err = l.svcCtx.DB.Transaction(func(tx *gorm.DB) error {
var deleteDevice user.Device
err = tx.Model(&deleteDevice).Where("id = ?", req.Id).First(&deleteDevice).Error
if err != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.QueueEnqueueError), "find device err: %v", err)
}
err = tx.Delete(deleteDevice).Error
if err != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseDeletedError), "delete device err: %v", err)
}
var userAuth user.AuthMethods
err = tx.Model(&userAuth).Where("auth_identifier = ? and auth_type = ?", deleteDevice.Identifier, "device").First(&userAuth).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
l.Infow("设备认证方法不存在,可能已被删除",
logger.Field("device_identifier", deleteDevice.Identifier),
logger.Field("user_id", userId))
return nil
}
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find device online record err: %v", err)
}
err = tx.Delete(&userAuth).Error
if err != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseDeletedError), "delete device online record err: %v", err)
}
l.Infow("设备解绑成功",
logger.Field("device_id", req.Id),
logger.Field("device_identifier", deviceIdentifier),
logger.Field("user_id", userId))
return nil
})
if err != nil {
return err
}
// 事务成功后进行缓存清理
l.clearUnbindDeviceCache(deviceIdentifier, userId, userInfo)
return nil
}
// clearUnbindDeviceCache 清除设备解绑相关的缓存
func (l *UnbindDeviceLogic) clearUnbindDeviceCache(deviceIdentifier string, userId int64, userInfo *user.User) {
// 1. 清除当前SessionId缓存使当前token失效
if sessionId := l.ctx.Value(constant.CtxKeySessionID); sessionId != nil {
sessionIdCacheKey := fmt.Sprintf("%v:%v", config.SessionIdKey, sessionId)
if err := l.svcCtx.Redis.Del(l.ctx, sessionIdCacheKey).Err(); err != nil {
l.Errorw("清理SessionId缓存失败",
logger.Field("error", err.Error()),
logger.Field("session_id", sessionId))
} else {
l.Infow("已清理SessionId缓存", logger.Field("session_id", sessionId))
}
}
// 2. 清除用户缓存
if err := l.svcCtx.UserModel.ClearUserCache(l.ctx, userInfo); err != nil {
l.Errorw("清理用户缓存失败",
logger.Field("error", err.Error()),
logger.Field("user_id", userId))
} else {
l.Infow("已清理用户缓存", logger.Field("user_id", userId))
}
// 3. 清除设备相关缓存
l.clearDeviceRelatedCache(deviceIdentifier, userId)
}
// clearDeviceRelatedCache 清除设备相关缓存
func (l *UnbindDeviceLogic) clearDeviceRelatedCache(deviceIdentifier string, userId int64) {
// 清除设备相关的缓存键
deviceCacheKeys := []string{
fmt.Sprintf("device:%s", deviceIdentifier),
fmt.Sprintf("user_device:%d", userId),
fmt.Sprintf("user_auth:%d", userId),
fmt.Sprintf("device_auth:%s", deviceIdentifier),
}
for _, key := range deviceCacheKeys {
if err := l.svcCtx.Redis.Del(l.ctx, key).Err(); err != nil {
l.Errorw("清除设备缓存失败",
logger.Field("error", err.Error()),
logger.Field("cache_key", key))
} else {
l.Infow("已清除设备缓存", logger.Field("cache_key", key))
}
}
}