149 lines
4.6 KiB
Go
149 lines
4.6 KiB
Go
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
|
||
}
|