From e61c1ec314d6bc7a0041705f547b415a40d73f06 Mon Sep 17 00:00:00 2001 From: zzw <1464003642@qq.com> Date: Thu, 3 Sep 2026 18:23:18 +0800 Subject: [PATCH] feat: verify code --- services/user/internal/logic/loginLogic.go | 68 +++++++++++++++++++- services/user/internal/logic/sendSmsLogic.go | 21 ++++++ 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/services/user/internal/logic/loginLogic.go b/services/user/internal/logic/loginLogic.go index bb1557e..f349890 100644 --- a/services/user/internal/logic/loginLogic.go +++ b/services/user/internal/logic/loginLogic.go @@ -3,11 +3,13 @@ package logic import ( "context" + "lone-services/pkg/modelbase" "lone-services/pkg/utils" "lone-services/pkg/validate" user "lone-services/rpc/user/pb" userconfig "lone-services/services/user/internal/config" "lone-services/services/user/internal/dao" + "lone-services/services/user/internal/model" "lone-services/services/user/internal/svc" "lone-services/services/user/validator" @@ -41,7 +43,7 @@ func (l *LoginLogic) Login(in *user.LoginReq) (*user.Response, error) { case dao.GrantTypePassword: return l.loginByPassword(req) case dao.GrantTypeSms: - return outResponse(utils.ErrorParams, "验证码登录暂未开放"), nil + return l.loginBySms(req) default: return outResponse(utils.ErrorParams, "不支持的登录方式"), nil } @@ -148,3 +150,67 @@ func (l *LoginLogic) loginByPassword(req validator.LoginValidator) (*user.Respon } return okResponse(ret), nil } + +func (l *LoginLogic) loginBySms(req validator.LoginValidator) (*user.Response, error) { + client, err := loadEnabledClient(req.ClientCode) + if err != nil { + l.Errorf("login load client: %v", err) + return failResponse(utils.Fail), nil + } + if !clientAllowsGrant(client.AllowedGrants, dao.GrantTypeSms) { + return outResponse(utils.ErrorParams, "该端不支持验证码登录"), nil + } + + if len(req.Mobile) != utils.NumberEleven { + return failResponse(utils.ErrorMobileError), nil + } + if ok, verifyErr := verifyAndConsumeSmsCode(l.ctx, dao.SmsSceneLogin, req.Mobile, req.SmsCode); verifyErr != nil { + l.Errorf("login verify sms: %v", verifyErr) + return failResponse(utils.Fail), nil + } else if !ok { + return outResponse(utils.ErrorParams, "验证码错误或已过期"), nil + } + + encryptMobile, encErr := utils.EncryptPhone(req.Mobile) + if encErr != nil { + l.Errorf("login encrypt mobile: %v", encErr) + return failResponse(utils.ErrorEncryptAesError), nil + } + + var exist dao.UserRow + userModel := model.UserModel{}.Init() + if getErr := userModel.GetOne(modelbase.Params{ + Eq: map[string]string{"mobile": encryptMobile}, + }, &exist); getErr != nil { + l.Errorf("login find user by mobile: %v", getErr) + return failResponse(utils.Fail), nil + } + if exist.Id < utils.NumberOne { + return failResponse(utils.ErrorNotFund), nil + } + if exist.Status == dao.StatusDisabled { + return outResponse(utils.Fail, "用户已禁用"), nil + } + + hasClient, clientErr := userHasEnabledClient(exist.Id, req.ClientCode) + if clientErr != nil { + l.Errorf("login check user client: %v", clientErr) + return failResponse(utils.Fail), nil + } + if !hasClient { + return outResponse(utils.ErrorParams, "该端未开通或已禁用"), nil + } + + row, userErr := loadEnabledUser(exist.Id) + if userErr != nil { + l.Errorf("login load user: %v", userErr) + return failResponse(utils.ErrorNotFund), nil + } + + ret, tokenErr := issueLoginToken(l.ctx, l.svcCtx.JWT, l.svcCtx.SaleSvcName, row, client) + if tokenErr != nil { + l.Errorf("login issue token: %v", tokenErr) + return failResponse(utils.Fail), nil + } + return okResponse(ret), nil +} diff --git a/services/user/internal/logic/sendSmsLogic.go b/services/user/internal/logic/sendSmsLogic.go index c5193e9..ec65892 100644 --- a/services/user/internal/logic/sendSmsLogic.go +++ b/services/user/internal/logic/sendSmsLogic.go @@ -104,6 +104,27 @@ func smsFreqRedisKey(scene int32, mobile string) string { return "sms:freq:" + strconv.Itoa(int(scene)) + ":" + mobile } +func verifyAndConsumeSmsCode(ctx context.Context, scene int32, mobile, code string) (bool, error) { + if code == utils.StringEmpty { + return false, nil + } + codeKey := smsCodeRedisKey(scene, mobile) + cached, err := redis.Client.Get(ctx, codeKey).Result() + if err == redis.Nil { + return false, nil + } + if err != nil { + return false, err + } + if cached != code { + return false, nil + } + if delErr := redis.Client.Del(ctx, codeKey).Err(); delErr != nil { + return false, delErr + } + return true, nil +} + func genDigitCode(length int) (string, error) { if length <= utils.NumberZero { return utils.StringEmpty, fmt.Errorf("invalid code length")