opt: 优化验证码发送逻辑,加入防刷验证

This commit is contained in:
RockYang 2023-07-04 17:15:02 +08:00
parent b9885e8de4
commit da88a501ad
5 changed files with 56 additions and 27 deletions

View File

@ -58,8 +58,10 @@ func (h *UserHandler) Register(c *gin.Context) {
// 检查验证码
key := CodeStorePrefix + data.Mobile
code, err := h.levelDB.Get(key)
if err != nil || int(code.(float64)) != data.Code {
var code int
err := h.levelDB.Get(key, &code)
if err != nil || code != data.Code {
logger.Info(code)
resp.ERROR(c, "短信验证码错误")
return
}
@ -356,8 +358,9 @@ func (h *UserHandler) BindMobile(c *gin.Context) {
// 检查验证码
key := CodeStorePrefix + data.Mobile
code, err := h.levelDB.Get(key)
if err != nil || int(code.(float64)) != data.Code {
var code int
err := h.levelDB.Get(key, &code)
if err != nil || code != data.Code {
resp.ERROR(c, "短信验证码错误")
return
}

View File

@ -7,6 +7,7 @@ import (
"chatplus/store"
"chatplus/utils"
"chatplus/utils/resp"
"fmt"
"time"
"github.com/gin-gonic/gin"
@ -20,8 +21,9 @@ type VerifyHandler struct {
db *store.LevelDB
}
const TokenStorePrefix = "/tokens/"
const CodeStorePrefix = "/codes/"
const TokenStorePrefix = "/verify/tokens/"
const CodeStorePrefix = "/verify/codes/"
const MobileStatPrefix = "/verify/stats/"
func NewVerifyHandler(app *core.AppServer, sms *service.AliYunSmsService, db *store.LevelDB) *VerifyHandler {
handler := &VerifyHandler{sms: sms, db: db}
@ -34,11 +36,24 @@ type VerifyToken struct {
Timestamp int64
}
// CodeStats 验证码发送统计
type CodeStats struct {
Mobile string
Count uint
Time int64
}
// Token 生成自验证 token
func (h *VerifyHandler) Token(c *gin.Context) {
// 确保是通过浏览器访问
// 如果不是通过浏览器访问,则返回错误的 token
if c.GetHeader("Sec-Fetch-Mode") != "cors" {
resp.HACKER(c)
token := fmt.Sprintf("%s:%d", utils.RandString(32), time.Now().Unix())
encrypt, err := utils.AesEncrypt(h.App.Config.AesEncryptKey, []byte(token))
if err != nil {
resp.ERROR(c, "Token 加密出错")
return
}
resp.SUCCESS(c, encrypt)
return
}
@ -85,17 +100,31 @@ func (h *VerifyHandler) SendMsg(c *gin.Context) {
return
}
_, err = h.db.Get(TokenStorePrefix + token.Token)
if err != nil {
resp.HACKER(c)
return
}
if time.Now().Unix()-token.Timestamp > 30 {
resp.ERROR(c, "Token 已过期,请刷新页面重试")
return
}
// 验证当前手机号发送次数24 小时内相同手机号只允许发送 2 次
var stat CodeStats
err = h.db.Get(MobileStatPrefix+data.Mobile, &stat)
if err != nil {
logger.Error(err)
stat = CodeStats{
Mobile: data.Mobile,
Count: 0,
Time: time.Now().Unix(),
}
} else if stat.Count == 2 {
if time.Now().Unix()-stat.Time > 86400 {
stat.Count = 0
stat.Time = time.Now().Unix()
} else {
resp.ERROR(c, "触发流量预警,请 24 小时后再操作!")
return
}
}
code := utils.RandomNumber(6)
err = h.sms.SendVerifyCode(data.Mobile, code)
if err != nil {
@ -112,5 +141,10 @@ func (h *VerifyHandler) SendMsg(c *gin.Context) {
return
}
// 更新发送次数
stat.Count = stat.Count + 1
_ = h.db.Put(MobileStatPrefix+data.Mobile, stat)
logger.Infof("%+v", stat)
resp.SUCCESS(c)
}

View File

@ -3,7 +3,6 @@ package store
import (
"chatplus/store/vo"
"encoding/json"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/util"
)
@ -30,19 +29,13 @@ func (db *LevelDB) Put(key string, value interface{}) error {
return db.driver.Put([]byte(key), bytes, nil)
}
func (db *LevelDB) Get(key string) (interface{}, error) {
func (db *LevelDB) Get(key string, value interface{}) error {
bytes, err := db.driver.Get([]byte(key), nil)
if err != nil {
return nil, err
return err
}
var value interface{}
err = json.Unmarshal(bytes, &value)
if err != nil {
return nil, err
}
return value, nil
return json.Unmarshal(bytes, &value)
}
func (db *LevelDB) Search(prefix string) []string {

View File

@ -17,8 +17,7 @@ import (
)
func main() {
//testAesEncrypt()
fmt.Println(utils.RandomNumber(6))
testAesEncrypt()
}
// Http client 取消操作

View File

@ -31,7 +31,7 @@ const sendMsg = () => {
httpGet('/api/verify/token').then(res => {
httpPost('/api/verify/sms', {token: res.data, mobile: props.mobile}).then(() => {
ElMessage.success('短信发送成功')
let time = 120
let time = 10
btnText.value = time
const handler = setInterval(() => {
time = time - 1