mingyang-admin-iot-app/rpc/internal/logic/code/get_verify_code_logic.go

149 lines
4.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package code
import (
"context"
"crypto/rand"
"fmt"
"github.com/zeromicro/go-zero/core/errorx"
"github.com/zeromicro/go-zero/core/logx"
"math/big"
"mingyang-admin-app-rpc/internal/logic/cacherepo"
"mingyang-admin-app-rpc/internal/svc"
"mingyang-admin-app-rpc/types/app"
"mingyang-admin-simple-admin-message/types/mcms"
"time"
)
type GetVerifyCodeLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
cacheRepo *cacherepo.CacheRepository
}
func NewGetVerifyCodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetVerifyCodeLogic {
return &GetVerifyCodeLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
cacheRepo: cacherepo.NewCacheRepository(ctx, svcCtx),
}
}
// GetVerifyCode 获取验证码
func (l *GetVerifyCodeLogic) GetVerifyCode(in *app.VerifyCodeReq) (*app.VerifyCodeResp, error) {
codeType := in.GetAccountType()
targetValue := in.GetValue()
minute := 5 * time.Minute
// 1. 检查缓存中是否有有效的验证码
cachedCode, err := l.CheckCacheVerificationCode(in)
if err != nil {
logx.Errorw("failed to check verification code cache", logx.Field("detail", err))
// 继续生成新验证码,不直接返回错误
}
var code string
// 2. 如果有缓存且有效,复用
if cachedCode != "" {
// 假设 cachedCode 是完整的 "captchaId:code" 格式
code = cachedCode
} else {
// 生成验证码
newCode, err := GenerateSecureCode()
if err != nil {
logx.Errorw("failed to generate verification code", logx.Field("detail", err))
return nil, err
}
code = newCode
}
// 4. 根据类型发送验证码
var sendErr error
switch codeType {
case app.AccountType_MOBILE:
// 调用短信服务发送验证码
sendErr = l.SendMobileMessage(in, code)
if sendErr != nil {
logx.Errorw("failed to send SMS verification code",
logx.Field("detail", sendErr),
logx.Field("mobile", targetValue))
}
case app.AccountType_EMAIL:
// 调用邮件服务发送验证码
sendErr = l.SendEmailMessage(in, code)
if sendErr != nil {
logx.Errorw("failed to send email verification code",
logx.Field("detail", sendErr),
logx.Field("email", targetValue))
}
default:
return nil, errorx.NewInvalidArgumentError("unsupported account type")
}
// 5. 如果发送失败,可以考虑清理缓存(可选)
if sendErr != nil {
// 可选:清理刚设置的缓存,避免无效验证码占用空间
// l.cacheRepo.DeleteVerificationCode(l.ctx, targetValue)
return nil, sendErr
}
cacheKey := fmt.Sprintf("email_verification_code:%s", in.Value)
fmt.Printf("cacheKey:%s", cacheKey)
// 7. 设置验证码到缓存
err = l.cacheRepo.SetVerificationCode(l.ctx, cacheKey, code, minute)
if err != nil {
logx.Errorw("failed to set verification code to cache", logx.Field("detail", err))
}
// 6. 返回响应
return &app.VerifyCodeResp{
CaptchaCode: code, // 返回纯数字验证码
Expire: uint32(minute.Seconds()),
}, nil
}
func (l *GetVerifyCodeLogic) SendMobileMessage(in *app.VerifyCodeReq, code string) error {
//l.cacheRepo.SetVerificationCode(l.ctx, in.Value, nil, 10*time.Minute)
return nil
}
func (l *GetVerifyCodeLogic) SendEmailMessage(in *app.VerifyCodeReq, code string) error {
_, err := l.svcCtx.McmsRpc.SendEmail(l.ctx, &mcms.EmailInfo{
Target: []string{in.Value},
Subject: in.Type.String(),
Content: fmt.Sprintf("验证码:%s", code),
})
if err != nil {
logx.Errorw("failed to send email", logx.Field("detail", err))
}
return nil
}
// CheckCacheVerificationCode 检查缓存中是否有验证码,并且未过期
func (l *GetVerifyCodeLogic) CheckCacheVerificationCode(in *app.VerifyCodeReq) (string, error) {
var cacheKey string
if in.AccountType == app.AccountType_EMAIL {
cacheKey = fmt.Sprintf("email_verification_code:%s", in.GetValue())
} else if in.AccountType == app.AccountType_MOBILE {
cacheKey = fmt.Sprintf("mobile_verification_code:%s", in.GetValue())
} else {
return "", nil
}
code, err := l.cacheRepo.GetVerificationCode(l.ctx, cacheKey)
if err != nil || code == nil {
logx.Errorw("failed to get verification code", logx.Field("detail", err))
return "", err
}
return code.Code, nil
}
// GenerateSecureCode 生成密码学安全的6位数字验证码
func GenerateSecureCode() (string, error) {
// 生成一个 [0, 999999] 范围内的大随机整数
max := big.NewInt(1000000) // 上限不包含,所以是 0-999999
_, err := rand.Int(rand.Reader, max)
if err != nil {
return "", err
}
// 格式化为6位数字符串不足6位前面补零
//return fmt.Sprintf("%06d", n.Int64()), nil
return "1234", nil
}