From a1859fdeb93522d8696b71a9390c886d894a1d6c Mon Sep 17 00:00:00 2001 From: liangzai <2440983361@qq.com> Date: Thu, 11 Dec 2025 19:01:28 +0800 Subject: [PATCH] fix --- .gitignore | 4 +- app/main/api/etc/main.yaml | 2 +- .../logic/agent/registerbyinvitecodelogic.go | 299 +++++++++++++++--- app/main/api/internal/service/userService.go | 79 ++--- 4 files changed, 300 insertions(+), 84 deletions(-) diff --git a/.gitignore b/.gitignore index 36ebdcb..554c52b 100644 --- a/.gitignore +++ b/.gitignore @@ -21,8 +21,8 @@ data/* # 打包出来的可执行文件 /app/api /app/main/api/main -/app/main/api/debug -/app/main/api/test +/app/main/api/_debug +/app/main/api/_test # 文档目录 documents/* diff --git a/app/main/api/etc/main.yaml b/app/main/api/etc/main.yaml index 7e84ad5..6e3ccc4 100644 --- a/app/main/api/etc/main.yaml +++ b/app/main/api/etc/main.yaml @@ -41,7 +41,7 @@ Wxpay: MchPublicKeyPath: "etc/merchant/pub_key.pem" MchPlatformRAS: "5630D013C88EA348BF66E642B6C39AA0180D4B15" NotifyUrl: "https://www.onecha.cn/api/v1/pay/wechat/callback" - RefundNotifyUrl: "https://www.onecha.cn/api/v1/wechat/refund_callback" + RefundNotifyUrl: "https://www.onecha.cn/api/v1/pay/wechat/refund_callback" Applepay: ProductionVerifyURL: "https://api.storekit.itunes.apple.com/inApps/v1/transactions/receipt" SandboxVerifyURL: "https://api.storekit-sandbox.itunes.apple.com/inApps/v1/transactions/receipt" diff --git a/app/main/api/internal/logic/agent/registerbyinvitecodelogic.go b/app/main/api/internal/logic/agent/registerbyinvitecodelogic.go index a1dc0eb..d5690e7 100644 --- a/app/main/api/internal/logic/agent/registerbyinvitecodelogic.go +++ b/app/main/api/internal/logic/agent/registerbyinvitecodelogic.go @@ -60,6 +60,35 @@ func (l *RegisterByInviteCodeLogic) RegisterByInviteCode(req *types.RegisterByIn } } + // 获取当前登录态(可能为空) + claims, err := ctxdata.GetClaimsFromCtx(l.ctx) + if err != nil && !errors.Is(err, ctxdata.ErrNoInCtx) { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户信息失败: %v", err) + } + + // 前置检查:如果当前用户是正式用户(有手机号),进行拦截检查 + if claims != nil { + currentUser, err := l.svcCtx.UserModel.FindOne(l.ctx, claims.UserId) + if err != nil && !errors.Is(err, model.ErrNotFound) { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询用户失败: %v", err) + } + if currentUser != nil && currentUser.Mobile.Valid && currentUser.Mobile.String != "" { + // 当前用户是正式用户,检查是否已是代理 + agent, err := l.svcCtx.AgentModel.FindOneByUserId(l.ctx, claims.UserId) + if err != nil && !errors.Is(err, model.ErrNotFound) { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询代理失败: %v", err) + } + if agent != nil { + return nil, errors.Wrapf(xerr.NewErrMsg("您已经是代理,不能重复注册"), "") + } + // 正式用户手机号必须匹配 + if currentUser.Mobile.String != encryptedMobile { + return nil, errors.Wrapf(xerr.NewErrMsg("请输入当前账号的手机号码"), "") + } + } + } + + // 验证邀请码是否有效 var inviteCodeModel *model.AgentInviteCode inviteCodeModel, err = l.svcCtx.AgentInviteCodeModel.FindOneByCode(l.ctx, req.Referrer) if err != nil && !errors.Is(err, model.ErrNotFound) { @@ -77,56 +106,43 @@ func (l *RegisterByInviteCodeLogic) RegisterByInviteCode(req *types.RegisterByIn } } - // 4. 使用事务处理注册 + // 使用事务处理注册 var userID string var agentID string var agentLevel int64 err = l.svcCtx.AgentInviteCodeModel.Trans(l.ctx, func(transCtx context.Context, session sqlx.Session) error { - // 4.1 检查用户是否已存在 - user, findUserErr := l.svcCtx.UserModel.FindOneByMobile(l.ctx, sql.NullString{String: encryptedMobile, Valid: true}) + // 1. 查找目标用户(通过手机号) + targetUser, findUserErr := l.svcCtx.UserModel.FindOneByMobile(transCtx, sql.NullString{String: encryptedMobile, Valid: true}) if findUserErr != nil && !errors.Is(findUserErr, model.ErrNotFound) { return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询用户失败, %v", findUserErr) } - if user == nil { - // 用户不存在,注册新用户 - userID, err = l.svcCtx.UserService.RegisterUser(l.ctx, encryptedMobile) - if err != nil { - return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "注册用户失败: %v", err) - } - } else { - // 用户已存在,检查是否已是代理 - existingAgent, err := l.svcCtx.AgentModel.FindOneByUserId(transCtx, user.Id) - if err != nil && !errors.Is(err, model.ErrNotFound) { - return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询代理信息失败, %v", err) - } - if existingAgent != nil { - return errors.Wrapf(xerr.NewErrMsg("您已经是代理"), "") - } - - // 检查用户是否有mobile绑定(没有mobile则不能成为代理) - // 如果是临时用户(微信环境下),需要先绑定手机号 - claims, err := ctxdata.GetClaimsFromCtx(l.ctx) - if err == nil && claims != nil { - // 获取用户的mobile信息 - if !user.Mobile.Valid || user.Mobile.String == "" { - // 临时用户(无mobile)不能直接成为代理,需要先绑定mobile - return errors.Wrapf(xerr.NewErrMsg("请先绑定手机号后再申请成为代理"), "") - } - // 检查是否已绑定手机号认证(用于确保后续可通过手机号登录) - userAuth, err := l.svcCtx.UserAuthModel.FindOneByUserIdAuthType(l.ctx, user.Id, claims.AuthType) - if err != nil && !errors.Is(err, model.ErrNotFound) { - return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询用户认证失败, %v", err) - } - if userAuth != nil && userAuth.AuthKey != claims.AuthKey { - return errors.Wrapf(xerr.NewErrMsg("该手机号已绑定其他微信号"), "") - } - } - - userID = user.Id + // 2. 获取当前登录态信息 + var currentUserID string + var currentAuthType string + var currentAuthKey string + if claims != nil { + currentUserID = claims.UserId + currentAuthType = claims.AuthType + currentAuthKey = claims.AuthKey } + // 3. 根据目标用户是否存在,处理用户和认证 + if targetUser == nil { + // 场景1: 手机号不存在 + userID, err = l.handleMobileNotExists(transCtx, session, encryptedMobile, currentUserID) + if err != nil { + return err + } + } else { + // 场景2: 手机号已存在 + userID, err = l.handleMobileExists(transCtx, session, targetUser, currentUserID, currentAuthType, currentAuthKey) + if err != nil { + return err + } + } + // 4. 处理邀请码和上级关系 var targetLevel int64 var parentAgentId string if inviteCodeModel != nil { @@ -156,7 +172,8 @@ func (l *RegisterByInviteCodeLogic) RegisterByInviteCode(req *types.RegisterByIn } } - // 4.3 创建代理记录 + // 5. 创建代理记录 + newAgent := &model.Agent{Id: uuid.NewString(), UserId: userID, Level: targetLevel, Mobile: encryptedMobile} if req.Region != "" { newAgent.Region = sql.NullString{String: req.Region, Valid: true} @@ -165,7 +182,7 @@ func (l *RegisterByInviteCodeLogic) RegisterByInviteCode(req *types.RegisterByIn newAgent.WechatId = sql.NullString{String: req.WechatId, Valid: true} } - // 4.4 处理上级关系 + // 6. 处理上级关系 if parentAgentId != "" { // 查找上级代理 parentAgent, err := l.svcCtx.AgentModel.FindOne(transCtx, parentAgentId) @@ -225,13 +242,13 @@ func (l *RegisterByInviteCodeLogic) RegisterByInviteCode(req *types.RegisterByIn } } - // 4.5 初始化钱包 + // 7. 初始化钱包 wallet := &model.AgentWallet{Id: uuid.NewString(), AgentId: agentID} if _, err := l.svcCtx.AgentWalletModel.Insert(transCtx, session, wallet); err != nil { return errors.Wrapf(err, "初始化钱包失败") } - // 4.6 更新邀请码状态 + // 8. 更新邀请码状态 // 钻石级别的邀请码只能使用一次,使用后立即失效 // 普通级别的邀请码可以无限使用,不更新状态 if targetLevel == 3 { @@ -247,7 +264,7 @@ func (l *RegisterByInviteCodeLogic) RegisterByInviteCode(req *types.RegisterByIn } } - // 4.7 记录邀请码使用历史(用于统计和查询) + // 9. 记录邀请码使用历史(用于统计和查询) if inviteCodeModel != nil { usage := &model.AgentInviteCodeUsage{Id: uuid.NewString(), InviteCodeId: inviteCodeModel.Id, Code: inviteCodeModel.Code, UserId: userID, AgentId: agentID, AgentLevel: targetLevel, UsedTime: time.Now()} if _, err := l.svcCtx.AgentInviteCodeUsageModel.Insert(transCtx, session, usage); err != nil { @@ -263,7 +280,7 @@ func (l *RegisterByInviteCodeLogic) RegisterByInviteCode(req *types.RegisterByIn return nil, err } - // 5. 生成并返回token + // 10. 生成并返回token token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成token失败: %v", err) @@ -361,3 +378,195 @@ func (l *RegisterByInviteCodeLogic) allocateAgentCode(ctx context.Context, sessi } return next, nil } + +// handleMobileNotExists 处理手机号不存在的情况 +func (l *RegisterByInviteCodeLogic) handleMobileNotExists(ctx context.Context, session sqlx.Session, encryptedMobile string, currentUserID string) (string, error) { + if currentUserID == "" { + // 场景1.1: 未登录 + 手机号不存在 -> 创建新用户 + newUser := &model.User{Id: uuid.NewString(), Mobile: sql.NullString{String: encryptedMobile, Valid: true}} + if _, err := l.svcCtx.UserModel.Insert(ctx, session, newUser); err != nil { + return "", errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建用户失败: %v", err) + } + // 创建 mobile 认证 + if _, err := l.svcCtx.UserAuthModel.Insert(ctx, session, &model.UserAuth{ + Id: uuid.NewString(), + UserId: newUser.Id, + AuthType: model.UserAuthTypeMobile, + AuthKey: encryptedMobile, + }); err != nil { + return "", errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建手机号认证失败: %v", err) + } + return newUser.Id, nil + } else { + // 场景1.2: 已登录临时用户 + 手机号不存在 -> 升级为正式用户 + // 前置检查已保证不是正式用户,所以这里一定是临时用户 + currentUser, err := l.svcCtx.UserModel.FindOne(ctx, currentUserID) + if err != nil { + return "", errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询当前用户失败: %v", err) + } + // 升级为正式用户 + currentUser.Mobile = sql.NullString{String: encryptedMobile, Valid: true} + if _, err := l.svcCtx.UserModel.Update(ctx, session, currentUser); err != nil { + return "", errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新手机号失败: %v", err) + } + // 创建 mobile 认证 + if _, err := l.svcCtx.UserAuthModel.Insert(ctx, session, &model.UserAuth{ + Id: uuid.NewString(), + UserId: currentUserID, + AuthType: model.UserAuthTypeMobile, + AuthKey: encryptedMobile, + }); err != nil { + return "", errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建手机号认证失败: %v", err) + } + return currentUserID, nil + } +} + +// handleMobileExists 处理手机号已存在的情况 +func (l *RegisterByInviteCodeLogic) handleMobileExists(ctx context.Context, session sqlx.Session, targetUser *model.User, currentUserID string, currentAuthType string, currentAuthKey string) (string, error) { + userID := targetUser.Id + + // 检查目标用户是否已是代理 + existingAgent, err := l.svcCtx.AgentModel.FindOneByUserId(ctx, userID) + if err != nil && !errors.Is(err, model.ErrNotFound) { + return "", errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询代理信息失败: %v", err) + } + if existingAgent != nil { + return "", errors.Wrapf(xerr.NewErrMsg("该手机号已经是代理,不能重复注册"), "") + } + + if currentUserID == "" { + // 场景2.1: 未登录 + 手机号存在 -> 直接使用目标用户(验证码已确认身份) + return userID, nil + } else if currentUserID == userID { + // 场景2.2: 已登录正式用户 + 手机号匹配 -> 直接使用 + // 前置检查已保证手机号匹配且不是代理 + return userID, nil + } else { + // 场景2.3: 已登录临时用户 + 手机号存在 -> 需要合并账号 + // 前置检查已保证是临时用户(不是正式用户) + return l.mergeTempUserToTarget(ctx, session, currentUserID, userID, currentAuthType, currentAuthKey) + } +} + +// mergeTempUserToTarget 合并临时用户到目标用户 +func (l *RegisterByInviteCodeLogic) mergeTempUserToTarget(ctx context.Context, session sqlx.Session, sourceUserID string, targetUserID string, currentAuthType string, currentAuthKey string) (string, error) { + // 检查目标用户是否已有该认证(除了UUID) + if currentAuthType != model.UserAuthTypeUUID { + targetAuth, err := l.svcCtx.UserAuthModel.FindOneByUserIdAuthType(ctx, targetUserID, currentAuthType) + if err != nil && !errors.Is(err, model.ErrNotFound) { + return "", errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查找认证信息失败: %v", err) + } + if targetAuth != nil && targetAuth.AuthKey != currentAuthKey { + // 目标用户已有该类型的其他认证,证明手机号绑定过其他微信等 + if currentAuthType == model.UserAuthTypeWxh5OpenID { + return "", errors.Wrapf(xerr.NewErrMsg("该手机号已绑定其他微信号"), "") + } + if currentAuthType == model.UserAuthTypeWxMiniOpenID { + return "", errors.Wrapf(xerr.NewErrMsg("该手机号已绑定其他微信号"), "") + } + return "", errors.Wrapf(xerr.NewErrMsg("该手机号已绑定其他终端"), "") + } + } + + // 查找当前认证 + existingAuth, err := l.svcCtx.UserAuthModel.FindOneByAuthTypeAuthKey(ctx, currentAuthType, currentAuthKey) + if err != nil && !errors.Is(err, model.ErrNotFound) { + return "", errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查找认证信息失败: %v", err) + } + + // 执行账号合并 + if err := l.mergeUserAccounts(ctx, session, sourceUserID, targetUserID, currentAuthType, currentAuthKey, existingAuth); err != nil { + return "", err + } + + return targetUserID, nil +} + +// mergeUserAccounts 合并账号:迁移认证、业务数据,删除临时用户 +func (l *RegisterByInviteCodeLogic) mergeUserAccounts(ctx context.Context, session sqlx.Session, sourceUserID string, targetUserID string, currentAuthType string, currentAuthKey string, existingAuth *model.UserAuth) error { + // 1) 认证绑定处理 + if existingAuth != nil && existingAuth.UserId != targetUserID { + // 认证存在但不属于目标用户,迁移到目标用户 + if currentAuthType == model.UserAuthTypeUUID { + // UUID替换策略:如果目标用户已有UUID认证,替换UUID;否则迁移认证 + targetUUIDAuth, _ := l.svcCtx.UserAuthModel.FindOneByUserIdAuthType(ctx, targetUserID, model.UserAuthTypeUUID) + if targetUUIDAuth != nil { + // 目标用户已有UUID认证,删除源认证并更新目标UUID + if err := l.svcCtx.UserAuthModel.Delete(ctx, session, existingAuth.Id); err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "删除旧UUID认证失败: %v", err) + } + if targetUUIDAuth.AuthKey != currentAuthKey { + targetUUIDAuth.AuthKey = currentAuthKey + if _, err := l.svcCtx.UserAuthModel.Update(ctx, session, targetUUIDAuth); err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新目标UUID认证失败: %v", err) + } + } + } else { + // 目标用户没有UUID认证,迁移源认证 + existingAuth.UserId = targetUserID + if _, err := l.svcCtx.UserAuthModel.Update(ctx, session, existingAuth); err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "迁移UUID认证失败: %v", err) + } + } + } else { + // 其他认证类型,直接迁移 + existingAuth.UserId = targetUserID + if _, err := l.svcCtx.UserAuthModel.Update(ctx, session, existingAuth); err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "迁移认证失败: %v", err) + } + } + } else if existingAuth == nil { + // 认证不存在,创建新认证 + if currentAuthType == model.UserAuthTypeUUID { + // UUID特殊处理:如果目标用户已有UUID认证,更新UUID;否则创建新认证 + targetUUIDAuth, _ := l.svcCtx.UserAuthModel.FindOneByUserIdAuthType(ctx, targetUserID, model.UserAuthTypeUUID) + if targetUUIDAuth != nil { + if targetUUIDAuth.AuthKey != currentAuthKey { + targetUUIDAuth.AuthKey = currentAuthKey + if _, err := l.svcCtx.UserAuthModel.Update(ctx, session, targetUUIDAuth); err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新目标UUID认证失败: %v", err) + } + } + } else { + if _, err := l.svcCtx.UserAuthModel.Insert(ctx, session, &model.UserAuth{ + Id: uuid.NewString(), + UserId: targetUserID, + AuthType: currentAuthType, + AuthKey: currentAuthKey, + }); err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建UUID认证失败: %v", err) + } + } + } else { + // 其他认证类型,创建新认证 + if _, err := l.svcCtx.UserAuthModel.Insert(ctx, session, &model.UserAuth{ + Id: uuid.NewString(), + UserId: targetUserID, + AuthType: currentAuthType, + AuthKey: currentAuthKey, + }); err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建认证失败: %v", err) + } + } + } + + // 2) 业务数据迁移:迁移订单和报告到目标用户 + if err := l.svcCtx.OrderModel.UpdateUserIDWithSession(ctx, session, sourceUserID, targetUserID); err != nil { + return errors.Wrapf(err, "迁移订单失败") + } + if err := l.svcCtx.QueryModel.UpdateUserIDWithSession(ctx, session, sourceUserID, targetUserID); err != nil { + return errors.Wrapf(err, "迁移报告失败") + } + + // 3) 删除临时用户 + sourceUser, err := l.svcCtx.UserModel.FindOne(ctx, sourceUserID) + if err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查找源用户失败: %v", err) + } + if err := l.svcCtx.UserModel.Delete(ctx, session, sourceUser.Id); err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "删除源用户失败: %v", err) + } + + return nil +} diff --git a/app/main/api/internal/service/userService.go b/app/main/api/internal/service/userService.go index f636082..0b63354 100644 --- a/app/main/api/internal/service/userService.go +++ b/app/main/api/internal/service/userService.go @@ -142,12 +142,10 @@ func (s *UserService) getAuthTypeByPlatform(platform string) string { } // RegisterUser 注册用户,返回用户ID -// 传入手机号,自动注册,如果ctx存在临时用户则临时用户转为正式用户 +// 只负责创建新用户(手机号不存在时),不处理合并逻辑 +// 如果有临时用户(claims),会将临时用户的认证绑定到新用户 func (s *UserService) RegisterUser(ctx context.Context, mobile string) (string, error) { - claims, err := ctxdata.GetClaimsFromCtx(ctx) - if err != nil && !errors.Is(err, ctxdata.ErrNoInCtx) { - return "", err - } + // 检查手机号是否已存在 user, err := s.userModel.FindOneByMobile(ctx, sql.NullString{String: mobile, Valid: true}) if err != nil && !errors.Is(err, model.ErrNotFound) { return "", err @@ -155,51 +153,60 @@ func (s *UserService) RegisterUser(ctx context.Context, mobile string) (string, if user != nil { return "", errors.New("用户已注册") } - // 普通注册 - if claims == nil { - var userId string - err = s.userModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error { - user := &model.User{Id: uuid.NewString(), Mobile: sql.NullString{String: mobile, Valid: true}} - if _, userInsertErr := s.userModel.Insert(ctx, session, user); userInsertErr != nil { - return userInsertErr - } - userId = user.Id - _, userAuthInsertErr := s.userAuthModel.Insert(ctx, session, &model.UserAuth{Id: uuid.NewString(), UserId: userId, AuthType: model.UserAuthTypeMobile, AuthKey: mobile}) - if userAuthInsertErr != nil { - return userAuthInsertErr - } - return nil - }) - if err != nil { - return "", err - } - return userId, nil - } - // 双重判断是否已经注册(根据mobile判断,而不是userType) - currentUser, err := s.userModel.FindOne(ctx, claims.UserId) - if err != nil && !errors.Is(err, model.ErrNotFound) { + // 获取当前登录态(可能为空) + claims, err := ctxdata.GetClaimsFromCtx(ctx) + if err != nil && !errors.Is(err, ctxdata.ErrNoInCtx) { return "", err } - if currentUser != nil && currentUser.Mobile.Valid && currentUser.Mobile.String != "" { - return "", errors.New("用户已注册") - } + var userId string - // 临时用户绑定mobile转正式注册 err = s.userModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error { + // 创建新用户 user := &model.User{Id: uuid.NewString(), Mobile: sql.NullString{String: mobile, Valid: true}} if _, userInsertErr := s.userModel.Insert(ctx, session, user); userInsertErr != nil { return userInsertErr } userId = user.Id - _, userAuthInsertErr := s.userAuthModel.Insert(ctx, session, &model.UserAuth{Id: uuid.NewString(), UserId: userId, AuthType: model.UserAuthTypeMobile, AuthKey: mobile}) + + // 创建 mobile 认证 + _, userAuthInsertErr := s.userAuthModel.Insert(ctx, session, &model.UserAuth{ + Id: uuid.NewString(), + UserId: userId, + AuthType: model.UserAuthTypeMobile, + AuthKey: mobile, + }) if userAuthInsertErr != nil { return userAuthInsertErr } - tempUserBindErr := s.TempUserBindUser(ctx, session, userId) - if tempUserBindErr != nil { - return tempUserBindErr + + // 如果有临时用户,将临时用户的认证绑定到新用户 + if claims != nil { + // 检查临时用户是否已有该认证类型 + existingAuth, err := s.userAuthModel.FindOneByAuthTypeAuthKey(ctx, claims.AuthType, claims.AuthKey) + if err != nil && !errors.Is(err, model.ErrNotFound) { + return err + } + // 如果认证不存在,创建新的认证绑定 + if existingAuth == nil { + _, err = s.userAuthModel.Insert(ctx, session, &model.UserAuth{ + Id: uuid.NewString(), + UserId: userId, + AuthType: claims.AuthType, + AuthKey: claims.AuthKey, + }) + if err != nil { + return err + } + } else if existingAuth.UserId != userId { + // 如果认证已存在但属于其他用户,迁移到新用户 + existingAuth.UserId = userId + if _, err := s.userAuthModel.Update(ctx, session, existingAuth); err != nil { + return err + } + } } + return nil }) if err != nil {