基于Golang Gin框架生成邮件验证码并校验服务完整实现
下面我将为你提供完整的数据库模型、API接口实现,并附上一篇适合发布在CSDN上的技术博客文章。
数据库模型 (model/email_code.go)
package model
import (
"time"
"gorm.io/gorm"
)
// EmailCode 邮箱验证码模型
type EmailCode struct {
gorm.Model
Email string `gorm:"size:100;not null;index"` // 邮箱地址
Code string `gorm:"size:10;not null"` // 验证码
ExpiresAt HTime `gorm:"not null"` // 过期时间
IsUsed bool `gorm:"default:false"` // 是否已使用
}
// HTime 自定义时间类型,用于处理数据库中的时间格式
type HTime struct {
time.Time
}
// GormDataType 实现 Gorm 的数据类型接口
func (t HTime) GormDataType() string {
return "datetime"
}
// Email SMTP配置模型
type Email struct {
Host string `json:"host"` // SMTP服务器地址
Port int `json:"port"` // 端口
Username string `json:"username"` // 用户名
Password string `json:"password"` // 密码
FormName string `json:"formName"` // 发件人名称
}
API接口实现 (api/mail.go)
package api
import (
"net/http"
"your_project/service"
"your_project/utils"
"github.com/gin-gonic/gin"
)
type MailApi struct {
mailService *service.MailService
}
func NewMailApi(mailService *service.MailService) *MailApi {
return &MailApi{mailService: mailService}
}
// SendCode 发送验证码接口
// @Summary 发送邮箱验证码
// @Description 向指定邮箱发送验证码
// @Tags 邮箱服务
// @Accept json
// @Produce json
// @Param email body string true "邮箱地址"
// @Success 200 {object} utils.Response
// @Failure 400 {object} utils.Response
// @Failure 500 {object} utils.Response
// @Router /mail/send-code [post]
func (a *MailApi) SendCode(c *gin.Context) {
var req struct {
Email string `json:"email" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
utils.FailWithMessage("参数错误", c)
return
}
if err := a.mailService.SendCode(req.Email); err != nil {
utils.FailWithMessage(err.Error(), c)
return
}
utils.OkWithMessage("验证码发送成功", c)
}
// VerifyCode 验证验证码接口
// @Summary 验证邮箱验证码
// @Description 验证邮箱和验证码是否匹配
// @Tags 邮箱服务
// @Accept json
// @Produce json
// @Param email body string true "邮箱地址"
// @Param code body string true "验证码"
// @Success 200 {object} utils.Response{data=bool}
// @Failure 400 {object} utils.Response
// @Failure 500 {object} utils.Response
// @Router /mail/verify-code [post]
func (a *MailApi) VerifyCode(c *gin.Context) {
var req struct {
Email string `json:"email" binding:"required"`
Code string `json:"code" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
utils.FailWithMessage("参数错误", c)
return
}
valid, err := a.mailService.VerifyEmailCode(req.Email, req.Code)
if err != nil {
utils.FailWithMessage(err.Error(), c)
return
}
if !valid {
utils.FailWithMessage("验证码错误或已过期", c)
return
}
utils.OkWithMessage("验证成功", c)
}
CSDN博客文章
Go语言实现高安全性的邮箱验证码服务
在现代Web应用中,邮箱验证码是用户注册、密码重置等关键操作的重要安全屏障。本文将详细介绍如何使用Go语言实现一个高安全性的邮箱验证码服务,包含频率限制、验证码生成、SMTP发送和自动清理等功能。
一、核心功能设计
我们的邮箱验证码服务需要实现以下核心功能:
- 验证码生成:生成高强度的随机验证码
- 频率限制:防止恶意用户频繁发送验证码
- 有效期控制:验证码5分钟内有效
- 自动清理:定期清理过期验证码
- 安全验证:验证码一次性使用
二、数据库设计
我们使用GORM定义邮箱验证码的数据模型:
type EmailCode struct {
gorm.Model
Email string `gorm:"size:100;not null;index"` // 邮箱地址
Code string `gorm:"size:10;not null"` // 验证码
ExpiresAt HTime `gorm:"not null"` // 过期时间
IsUsed bool `gorm:"default:false"` // 是否已使用
}
三、核心服务实现
1. 验证码生成
我们使用crypto/rand
生成高安全性的随机验证码:
func (s *MailService) generateSecureCode() (string, error) {
const charset = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ"
b := make([]byte, 6)
for i := range b {
n, err := rand.Int(rand.Reader, big.NewInt(int64(len(charset))))
if err != nil {
return "", fmt.Errorf("随机数生成失败: %w", err)
}
b[i] = charset[n.Int64()]
}
return string(b), nil
}
2. 频率限制实现
使用sync.Map
实现内存级的频率控制:
// 频率控制
if lastSent, ok := s.rateLimiter.Load(toEmail); ok {
now := time.Now()
if now.Sub(lastSent.(time.Time)) < 60*time.Second {
return errors.New("操作频率限制:60秒内只能发送一次")
}
}
3. 邮件发送实现
使用gomail
库发送HTML格式的验证码邮件:
e := email.NewEmail()
e.From = s.smtpConfig.FormName
e.To = []string{toEmail}
e.Subject = "验证码通知"
e.HTML = []byte(fmt.Sprintf(`
<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
<h2 style="color: #1890ff;">您的验证码</h2>
<p>验证码:<strong style="font-size: 18px;">%s</strong></p>
<p style="color: #999;">该验证码5分钟内有效,请勿泄露给他人</p>
</div>
`, code))
4. 自动清理任务
启动goroutine定期清理过期验证码:
func (s *MailService) StartCleanupTask(ctx context.Context) {
go func() {
ticker := time.NewTicker(1 * time.Hour)
defer ticker.Stop()
for {
select {
case <-ticker.C:
s.db.Where("expires_at < ?", utils.HTime{Time: time.Now()}).Delete(&model.EmailCode{})
case <-ctx.Done():
return
}
}
}()
}
四、API接口设计
我们提供两个RESTful API接口:
- 发送验证码接口
POST /mail/send-code
- 验证验证码接口
POST /mail/verify-code
接口使用Swagger文档化,方便前端对接。
五、安全考虑
- 验证码复杂度:使用安全的随机数生成器,排除易混淆字符
- 频率限制:60秒内只能发送一次验证码
- 有效期控制:验证码5分钟后自动失效
- 一次性使用:验证码验证后标记为已使用
- HTTPS传输:确保验证码在传输过程中加密
六、总结
本文实现的邮箱验证码服务具有以下优点:
- 高安全性:使用加密随机数生成验证码
- 高性能:内存级频率控制减少数据库压力
- 易扩展:可轻松集成到现有系统中
- 自动化:自动清理过期数据
完整代码已提供,你可以直接集成到自己的项目中。如果你有任何问题,欢迎在评论区留言讨论。
这篇博客文章详细介绍了实现思路和技术细节,适合发布在CSDN等技术社区。文章结构清晰,代码示例完整,能够帮助其他开发者理解并实现类似功能。