refactor(auth): 优化设备登录逻辑,移除冗余代码并添加设备缓存
Build docker and publish / build (20.15.1) (push) Failing after 6m39s
Build docker and publish / build (20.15.1) (push) Failing after 6m39s
feat(database): 添加用户算法和盐字段的迁移脚本 fix(subscribe): 修复服务器用户列表缓存问题,临时禁用缓存 style(model): 清理用户模型注释,简化代码结构 chore: 删除无用脚本和测试文件 docs: 添加用户绑定流程文档 perf(login): 优化设备登录性能,添加设备缓存键 fix(unbind): 修复设备解绑时的缓存清理逻辑 refactor(verify): 简化邮箱验证逻辑,移除冗余代码 build(docker): 更新Dockerfile配置,使用scratch基础镜像
This commit is contained in:
@@ -246,14 +246,14 @@ func (l *BindEmailWithVerificationLogic) transferDeviceToEmailUser(deviceUserId,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 5. 强制清除邮箱用户的所有相关缓存(确保获取最新数据)// 清除邮箱用户缓存
|
||||
emailUser, _ := l.svcCtx.UserModel.FindOne(l.ctx, emailUserId)
|
||||
if emailUser != nil {
|
||||
// 清除用户的批量相关缓存(包括设备、认证方法等)
|
||||
if err := l.svcCtx.UserModel.BatchClearRelatedCache(l.ctx, emailUser); err != nil {
|
||||
l.Errorw("清理邮箱用户相关缓存失败", logger.Field("error", err.Error()), logger.Field("user_id", emailUser.Id))
|
||||
}
|
||||
}
|
||||
// // 5. 强制清除邮箱用户的所有相关缓存(确保获取最新数据)// 清除邮箱用户缓存
|
||||
// emailUser, _ := l.svcCtx.UserModel.FindOne(l.ctx, emailUserId)
|
||||
// if emailUser != nil {
|
||||
// // 清除用户的批量相关缓存(包括设备、认证方法等)
|
||||
// if err := l.svcCtx.UserModel.BatchClearRelatedCache(l.ctx, emailUser); err != nil {
|
||||
// l.Errorw("清理邮箱用户相关缓存失败", logger.Field("error", err.Error()), logger.Field("user_id", emailUser.Id))
|
||||
// }
|
||||
// }
|
||||
|
||||
// 6. 清除设备相关缓存
|
||||
// l.clearDeviceRelatedCache(deviceIdentifier, deviceUserId, emailUserId)
|
||||
|
||||
@@ -41,11 +41,7 @@ func (l *UnbindDeviceLogic) UnbindDevice(req *types.UnbindDeviceRequest) error {
|
||||
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 {
|
||||
return 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 {
|
||||
@@ -59,9 +55,6 @@ func (l *UnbindDeviceLogic) UnbindDevice(req *types.UnbindDeviceRequest) error {
|
||||
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)
|
||||
@@ -72,68 +65,13 @@ func (l *UnbindDeviceLogic) UnbindDevice(req *types.UnbindDeviceRequest) error {
|
||||
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))
|
||||
|
||||
//remove device cache
|
||||
deviceCacheKey := fmt.Sprintf("%v:%v", config.DeviceCacheKeyKey, deleteDevice.Identifier)
|
||||
if sessionId, err := l.svcCtx.Redis.Get(l.ctx, deviceCacheKey).Result(); err == nil && sessionId != "" {
|
||||
_ = l.svcCtx.Redis.Del(l.ctx, deviceCacheKey).Err()
|
||||
sessionIdCacheKey := fmt.Sprintf("%v:%v", config.SessionIdKey, sessionId)
|
||||
_ = l.svcCtx.Redis.Del(l.ctx, sessionIdCacheKey).Err()
|
||||
}
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,16 +15,13 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// VerifyEmailLogic 邮箱验证逻辑结构体
|
||||
// 用于处理用户邮箱验证码验证的业务逻辑
|
||||
type VerifyEmailLogic struct {
|
||||
logger.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
// NewVerifyEmailLogic 创建邮箱验证逻辑实例
|
||||
// 用于初始化邮箱验证处理器
|
||||
// Verify Email
|
||||
func NewVerifyEmailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *VerifyEmailLogic {
|
||||
return &VerifyEmailLogic{
|
||||
Logger: logger.WithContext(ctx),
|
||||
@@ -33,68 +30,46 @@ func NewVerifyEmailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Verif
|
||||
}
|
||||
}
|
||||
|
||||
// CacheKeyPayload Redis缓存中验证码的数据结构
|
||||
// 用于存储验证码和最后发送时间
|
||||
type CacheKeyPayload struct {
|
||||
Code string `json:"code"` // 验证码
|
||||
LastAt int64 `json:"lastAt"` // 最后发送时间戳
|
||||
Code string `json:"code"`
|
||||
LastAt int64 `json:"lastAt"`
|
||||
}
|
||||
|
||||
// VerifyEmail 验证邮箱验证码
|
||||
// 该方法用于验证用户输入的邮箱验证码是否正确,并将邮箱标记为已验证状态
|
||||
func (l *VerifyEmailLogic) VerifyEmail(req *types.VerifyEmailRequest) error {
|
||||
// 构建Redis缓存键,格式:认证码缓存前缀:安全标识:邮箱地址
|
||||
cacheKey := fmt.Sprintf("%s:%s:%s", config.AuthCodeCacheKey, constant.Security, req.Email)
|
||||
|
||||
// 从Redis中获取验证码缓存数据
|
||||
value, err := l.svcCtx.Redis.Get(l.ctx, cacheKey).Result()
|
||||
if err != nil {
|
||||
l.Errorw("Redis Error", logger.Field("error", err.Error()), logger.Field("cacheKey", cacheKey))
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error")
|
||||
}
|
||||
|
||||
// 解析缓存中的验证码数据
|
||||
var payload CacheKeyPayload
|
||||
err = json.Unmarshal([]byte(value), &payload)
|
||||
if err != nil {
|
||||
l.Errorw("Redis Error", logger.Field("error", err.Error()), logger.Field("cacheKey", cacheKey))
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error")
|
||||
}
|
||||
|
||||
// 验证用户输入的验证码是否与缓存中的验证码匹配
|
||||
if payload.Code != req.Code {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error")
|
||||
}
|
||||
|
||||
// 验证成功后删除Redis中的验证码缓存(一次性使用)
|
||||
l.svcCtx.Redis.Del(l.ctx, cacheKey)
|
||||
|
||||
// 从上下文中获取当前用户信息
|
||||
u, ok := l.ctx.Value(constant.CtxKeyUser).(*user.User)
|
||||
if !ok {
|
||||
logger.Error("current user is not found in context")
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access")
|
||||
}
|
||||
|
||||
// 根据邮箱地址查找用户的邮箱认证方式记录
|
||||
method, err := l.svcCtx.UserModel.FindUserAuthMethodByOpenID(l.ctx, "email", req.Email)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "FindUserAuthMethodByOpenID error")
|
||||
}
|
||||
|
||||
// 验证邮箱认证记录是否属于当前用户(安全检查)
|
||||
if method.UserId != u.Id {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "invalid access")
|
||||
}
|
||||
|
||||
// 将邮箱标记为已验证状态
|
||||
method.Verified = true
|
||||
|
||||
// 更新数据库中的认证方式记录
|
||||
err = l.svcCtx.UserModel.UpdateUserAuthMethods(l.ctx, method)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "UpdateUserAuthMethods error")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user