Some checks failed
Build docker and publish / build (20.15.1) (push) Has been cancelled
refactor: 重构用户模型和密码验证逻辑 feat(epay): 添加支付类型支持 docs: 添加安装和配置指南文档 fix: 修复优惠券过期检查逻辑 perf: 优化设备解绑缓存清理流程 test: 添加密码验证测试用例 chore: 更新依赖版本
140 lines
4.4 KiB
Go
140 lines
4.4 KiB
Go
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))
|
||
}
|
||
}
|
||
}
|