You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
OneAuth/models/verification.go

67 lines
2.0 KiB
Go

//
// Copyright (C) 2024 veypi <i@veypi.com>
// 2025-03-04 16:08:06
// Distributed under terms of the MIT license.
//
package models
import (
"time"
"github.com/veypi/vigo"
)
// VerificationCode 统一验证码表(邮箱 + 短信)
type VerificationCode struct {
vigo.Model
Target string `gorm:"index;size:100;not null" json:"target"` // 邮箱或手机号
Type string `gorm:"index;size:20;not null" json:"type"` // "email" | "sms"
Code string `gorm:"size:10;not null" json:"-"` // 验证码(不返回)
Purpose string `gorm:"index;size:20;not null" json:"purpose"` // register/login/reset_password/bind
Status CodeStatus `gorm:"default:0" json:"status"`
ExpiresAt time.Time `gorm:"index;not null" json:"expires_at"`
UsedAt *time.Time `json:"used_at"`
Attempts int `gorm:"default:0" json:"attempts"`
SendCount int `gorm:"default:1" json:"send_count"`
RemoteIP string `gorm:"size:50" json:"remote_ip"`
}
// TableName 表名
func (VerificationCode) TableName() string {
return "verification_codes"
}
// CodeStatus 验证码状态
type CodeStatus int
const (
CodeStatusPending CodeStatus = iota // 待验证
CodeStatusUsed // 已使用
CodeStatusExpired // 已过期
CodeStatusFailed // 验证失败(超过最大尝试次数)
)
// IsExpired 检查验证码是否过期
func (c *VerificationCode) IsExpired() bool {
return time.Now().After(c.ExpiresAt)
}
// CanRetry 检查是否可以重试验证
func (c *VerificationCode) CanRetry(maxAttempts int) bool {
return c.Status == CodeStatusPending && c.Attempts < maxAttempts && !c.IsExpired()
}
// IsUsed 检查是否已使用
func (c *VerificationCode) IsUsed() bool {
return c.Status == CodeStatusUsed && c.UsedAt != nil
}
// 验证码用途常量
const (
CodePurposeRegister = "register"
CodePurposeLogin = "login"
CodePurposeResetPassword = "reset_password"
CodePurposeBind = "bind"
)