feat: verify code
This commit is contained in:
@@ -3,11 +3,13 @@ package logic
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"lone-services/pkg/modelbase"
|
||||||
"lone-services/pkg/utils"
|
"lone-services/pkg/utils"
|
||||||
"lone-services/pkg/validate"
|
"lone-services/pkg/validate"
|
||||||
user "lone-services/rpc/user/pb"
|
user "lone-services/rpc/user/pb"
|
||||||
userconfig "lone-services/services/user/internal/config"
|
userconfig "lone-services/services/user/internal/config"
|
||||||
"lone-services/services/user/internal/dao"
|
"lone-services/services/user/internal/dao"
|
||||||
|
"lone-services/services/user/internal/model"
|
||||||
"lone-services/services/user/internal/svc"
|
"lone-services/services/user/internal/svc"
|
||||||
"lone-services/services/user/validator"
|
"lone-services/services/user/validator"
|
||||||
|
|
||||||
@@ -41,7 +43,7 @@ func (l *LoginLogic) Login(in *user.LoginReq) (*user.Response, error) {
|
|||||||
case dao.GrantTypePassword:
|
case dao.GrantTypePassword:
|
||||||
return l.loginByPassword(req)
|
return l.loginByPassword(req)
|
||||||
case dao.GrantTypeSms:
|
case dao.GrantTypeSms:
|
||||||
return outResponse(utils.ErrorParams, "验证码登录暂未开放"), nil
|
return l.loginBySms(req)
|
||||||
default:
|
default:
|
||||||
return outResponse(utils.ErrorParams, "不支持的登录方式"), nil
|
return outResponse(utils.ErrorParams, "不支持的登录方式"), nil
|
||||||
}
|
}
|
||||||
@@ -148,3 +150,67 @@ func (l *LoginLogic) loginByPassword(req validator.LoginValidator) (*user.Respon
|
|||||||
}
|
}
|
||||||
return okResponse(ret), nil
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -104,6 +104,27 @@ func smsFreqRedisKey(scene int32, mobile string) string {
|
|||||||
return "sms:freq:" + strconv.Itoa(int(scene)) + ":" + mobile
|
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) {
|
func genDigitCode(length int) (string, error) {
|
||||||
if length <= utils.NumberZero {
|
if length <= utils.NumberZero {
|
||||||
return utils.StringEmpty, fmt.Errorf("invalid code length")
|
return utils.StringEmpty, fmt.Errorf("invalid code length")
|
||||||
|
|||||||
Reference in New Issue
Block a user