package service import ( "blazing/common/data/share" "blazing/cool" v1 "blazing/modules/base/api/v1" "blazing/modules/base/model" "context" "crypto/tls" "fmt" "html/template" "log" "net" "net/smtp" "strings" "time" "github.com/gogf/gf/v2/crypto/gmd5" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gcache" "github.com/gogf/gf/v2/util/gconv" ) func (s *BaseSysLoginService) Reg(ctx context.Context, req *v1.BaseOpenLoginReq) (result *TokenResult, err error) { var ( captchaId = req.CaptchaId verifyCode = req.VerifyCode password = req.Password username = req.Username baseSysUser = model.NewBaseSysUser() ) vcode, _ := cool.CacheManager.Get(ctx, "login:"+captchaId) if vcode.String() != verifyCode { err = gerror.New("验证码错误") return } md5password, _ := gmd5.Encrypt(password) var user *model.BaseSysUser cool.DBM(baseSysUser).Where("username=?", username).Where("password=?", md5password).Where("status=?", 1).Scan(&user) if user == nil { err = gerror.New("账户或密码不正确~") return } result, err = s.generateTokenByUser(ctx, user) if err != nil { return } return } // 10分钟内限制请求 ip->次数 邮箱->次数 // 验证码对redis传,防止被重复操作 // var emailcache = expirable.NewLRU[string, int](0, nil, time.Millisecond*10) var ipcache = gcache.New(1000) func (s *BaseSysLoginService) Email(ctx context.Context, req *v1.BaseOpenEmailReq) (result *TokenResult, err error) { var ( r = g.RequestFromCtx(ctx) //baseSysUser = model.NewBaseSysUser() ) ip := r.GetClientIp() v, ok2 := ipcache.Get(context.Background(), ip) if ok2 != nil || v.Int() > 3 { return nil, gerror.New("操作过于频繁,请稍后再试") } ipcache.Set(context.Background(), ip, v.Int()+1, 10*time.Minute) ok1, _ := share.ShareManager.EmailCodeExists(req.Email) if ok1 { return nil, gerror.New("注册码已下发 ") } // 发送验证码 code, _ := share.ShareManager.SaveEmailCode(req.Email, time.Millisecond*10) SendVerificationCode(req.Email, code) return } // SMTPConfig 邮件发送配置 type SMTPConfig struct { Host string // SMTP服务器地址 Port int // SMTP端口 Username string // 发件人邮箱 Password string // SMTP授权密码 } // 默认腾讯企业邮配置(可根据实际情况修改) var DefaultSMTPConfig = SMTPConfig{ Host: "smtp.qcloudmail.com", Port: 465, Username: "1@seersun.com", Password: "z1Tq6v45vXbYQGBrqOUE", } // VerificationCodeData 验证码邮件模板数据 type VerificationCodeData struct { Code string // 验证码 ValidMin int // 有效期(分钟) Platform string // 平台名称 Hotline string // 客服热线 } // 验证码邮件HTML模板 const verificationCodeTemplate = ` 验证码通知
注册
验证码通知

尊敬的用户,您好!您正在进行身份验证操作,本次验证码如下:

{{.Code}}

⚠ 验证码有效期为{{.ValidMin}}分钟,请尽快完成验证。如非本人操作,请忽略此邮件。

` // SendVerificationCode 发送验证码邮件 // to: 收件人邮箱 // code: 验证码 // 返回错误信息 func SendVerificationCode(to string, code int) error { // 模板数据 data := VerificationCodeData{ Code: gconv.String(code), ValidMin: 10, // 有效期10分钟 Platform: "骄阳号", // 可替换为实际平台名称 Hotline: "seersun.com", // 可替换为实际客服热线 } // 生成邮件内容 body, err := renderTemplate(verificationCodeTemplate, data) if err != nil { return fmt.Errorf("渲染模板失败: %w", err) } // 发送邮件 return sendMail( DefaultSMTPConfig, to, "验证码通知", body, ) } // renderTemplate 渲染模板 func renderTemplate(tplStr string, data interface{}) (string, error) { tpl, err := template.New("verification").Parse(tplStr) if err != nil { return "", err } buf := new(strings.Builder) if err := tpl.Execute(buf, data); err != nil { return "", err } return buf.String(), nil } // sendMail 发送邮件核心函数 func sendMail(config SMTPConfig, to, subject, body string) error { // 构建邮件头部 header := make(map[string]string) header["From"] = fmt.Sprintf("骄阳号 <%s>", config.Username) header["To"] = to header["Subject"] = subject header["Content-Type"] = "text/html; charset=UTF-8" // 拼接邮件内容 message := "" for k, v := range header { message += fmt.Sprintf("%s: %s\r\n", k, v) } message += "\r\n" + body // 认证信息 auth := smtp.PlainAuth( "", config.Username, config.Password, config.Host, ) // 发送邮件 addr := fmt.Sprintf("%s:%d", config.Host, config.Port) return SendMailWithTLS(addr, auth, config.Username, []string{to}, []byte(message)) } // Dial 创建TLS连接的SMTP客户端 func Dial(addr string) (*smtp.Client, error) { conn, err := tls.Dial("tcp", addr, nil) if err != nil { log.Println("tls.Dial Error:", err) return nil, err } host, _, _ := net.SplitHostPort(addr) return smtp.NewClient(conn, host) } // SendMailWithTLS 使用TLS发送邮件 func SendMailWithTLS(addr string, auth smtp.Auth, from string, to []string, msg []byte) (err error) { c, err := Dial(addr) if err != nil { log.Println("创建SMTP客户端失败:", err) return err } defer c.Close() if auth != nil { if ok, _ := c.Extension("AUTH"); ok { if err = c.Auth(auth); err != nil { log.Println("认证失败:", err) return err } } } if err = c.Mail(from); err != nil { return err } for _, addr := range to { if err = c.Rcpt(addr); err != nil { return err } } w, err := c.Data() if err != nil { return err } _, err = w.Write(msg) if err != nil { return err } if err = w.Close(); err != nil { return err } return c.Quit() } // TestSendVerificationCode 测试发送验证码邮件 func TestSendVerificationCode() error { // 测试发送验证码为123456的邮件 return SendVerificationCode("3361562035@qq.com", 123456) }