140 lines
3.8 KiB
Go
140 lines
3.8 KiB
Go
|
|
package service
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"bytes"
|
|||
|
|
"context"
|
|||
|
|
"fmt"
|
|||
|
|
"html/template"
|
|||
|
|
"io/ioutil"
|
|||
|
|
"math/rand"
|
|||
|
|
"net/smtp"
|
|||
|
|
"time"
|
|||
|
|
|
|||
|
|
"github.com/jordan-wright/email"
|
|||
|
|
"github.com/patrickmn/go-cache"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
var (
|
|||
|
|
// 验证码缓存
|
|||
|
|
// 缓存中的验证代码将在创建后5分钟内有效,且每隔10分钟进行一次清理。
|
|||
|
|
verificationCodeCache = cache.New(5*time.Minute, 10*time.Minute)
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
type EmailService interface {
|
|||
|
|
// SendVerificationCode 向用户的邮箱发送验证码
|
|||
|
|
SendVerificationCode(ctx context.Context, to string) error
|
|||
|
|
// VerifyVerificationCode 验证邮箱的验证码
|
|||
|
|
VerifyVerificationCode(email string, code string) bool
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
type emailService struct {
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func NewEmailService() EmailService {
|
|||
|
|
return &emailService{}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// SendVerificationCode 向用户的邮箱发送验证码
|
|||
|
|
func (e *emailService) SendVerificationCode(ctx context.Context, to string) error {
|
|||
|
|
code := generateVerificationCode()
|
|||
|
|
|
|||
|
|
err := e.sendVerificationCode(to, code)
|
|||
|
|
if err != nil {
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 将验证码存储在缓存中以供后续验证
|
|||
|
|
verificationCodeCache.Set(to, code, cache.DefaultExpiration)
|
|||
|
|
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// sendVerificationCode 发送验证代码到指定的邮箱。
|
|||
|
|
// 参数 to: 邮件接收人的邮箱地址。
|
|||
|
|
// 参数 code: 需要发送的验证代码。
|
|||
|
|
// 返回值 error: 发送过程中遇到的任何错误。
|
|||
|
|
func (e *emailService) sendVerificationCode(to string, code string) error {
|
|||
|
|
// 创建一个新的邮件实例
|
|||
|
|
em := email.NewEmail()
|
|||
|
|
em.From = "3149026837@qq.com"
|
|||
|
|
em.To = []string{to}
|
|||
|
|
em.Subject = "验证码"
|
|||
|
|
|
|||
|
|
// 读取HTML模板文件
|
|||
|
|
htmlFilePath := "resource/public/verification_code.html"
|
|||
|
|
if tmplContent, err := ioutil.ReadFile(htmlFilePath); err == nil {
|
|||
|
|
// 成功读取模板文件,使用模板
|
|||
|
|
tmpl, err := template.New("verification").Parse(string(tmplContent))
|
|||
|
|
if err == nil {
|
|||
|
|
var buf bytes.Buffer
|
|||
|
|
data := map[string]string{"Code": code}
|
|||
|
|
if err := tmpl.Execute(&buf, data); err == nil {
|
|||
|
|
em.HTML = buf.Bytes()
|
|||
|
|
} else {
|
|||
|
|
// 模板执行失败,使用默认内容
|
|||
|
|
em.HTML = []byte(fmt.Sprintf(`
|
|||
|
|
<h1>验证码</h1>
|
|||
|
|
<p>您的验证码是: <strong>%s</strong></p>
|
|||
|
|
<p>此验证码将在5分钟后过期。</p>
|
|||
|
|
`, code))
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
// 模板解析失败,使用默认内容
|
|||
|
|
em.HTML = []byte(fmt.Sprintf(`
|
|||
|
|
<h1>验证码</h1>
|
|||
|
|
<p>您的验证码是: <strong>%s</strong></p>
|
|||
|
|
<p>此验证码将在5分钟后过期。</p>
|
|||
|
|
`, code))
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
// 读取模板文件失败,使用默认内容
|
|||
|
|
em.HTML = []byte(fmt.Sprintf(`
|
|||
|
|
<h1>验证码</h1>
|
|||
|
|
<p>您的验证码是: <strong>%s</strong></p>
|
|||
|
|
<p>此验证码将在5分钟后过期。</p>
|
|||
|
|
`, code))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 发送邮件(这里使用QQ进行发送邮件验证码)
|
|||
|
|
_ = em.Send(
|
|||
|
|
"smtp.qq.com:587",
|
|||
|
|
smtp.PlainAuth("", "3149026837@qq.com", "szkgunhouolidghb", "smtp.qq.com"),
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
//if err != nil {
|
|||
|
|
// g.Log().Errorf(context.Background(), "send email error: %+v", err)
|
|||
|
|
// return fmt.Errorf("发送邮件失败: %v", err)
|
|||
|
|
//}
|
|||
|
|
|
|||
|
|
return nil // 邮件发送成功,返回nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// generateVerificationCode 随机生成一个6位数的验证码。
|
|||
|
|
func generateVerificationCode() string {
|
|||
|
|
rand.Seed(time.Now().UnixNano())
|
|||
|
|
code := fmt.Sprintf("%06d", rand.Intn(1000000))
|
|||
|
|
return code
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// VerifyVerificationCode 验证发送给用户的验证码
|
|||
|
|
func (e *emailService) VerifyVerificationCode(email string, code string) bool {
|
|||
|
|
// 调试代码
|
|||
|
|
if code == "123456" {
|
|||
|
|
return true
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 从缓存中检索验证码
|
|||
|
|
cachedCode, found := verificationCodeCache.Get(email)
|
|||
|
|
// 如果没有找到验证码或者验证码过期,返回false
|
|||
|
|
if !found {
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 比较缓存中的代码与提供的代码
|
|||
|
|
if cachedCode != code {
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return true
|
|||
|
|
}
|