mirror of
				https://github.com/yangjian102621/geekai.git
				synced 2025-11-04 16:23:42 +08:00 
			
		
		
		
	opt: 优化验证码发送逻辑,加入防刷验证
This commit is contained in:
		@@ -58,8 +58,10 @@ func (h *UserHandler) Register(c *gin.Context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// 检查验证码
 | 
						// 检查验证码
 | 
				
			||||||
	key := CodeStorePrefix + data.Mobile
 | 
						key := CodeStorePrefix + data.Mobile
 | 
				
			||||||
	code, err := h.levelDB.Get(key)
 | 
						var code int
 | 
				
			||||||
	if err != nil || int(code.(float64)) != data.Code {
 | 
						err := h.levelDB.Get(key, &code)
 | 
				
			||||||
 | 
						if err != nil || code != data.Code {
 | 
				
			||||||
 | 
							logger.Info(code)
 | 
				
			||||||
		resp.ERROR(c, "短信验证码错误")
 | 
							resp.ERROR(c, "短信验证码错误")
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -356,8 +358,9 @@ func (h *UserHandler) BindMobile(c *gin.Context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// 检查验证码
 | 
						// 检查验证码
 | 
				
			||||||
	key := CodeStorePrefix + data.Mobile
 | 
						key := CodeStorePrefix + data.Mobile
 | 
				
			||||||
	code, err := h.levelDB.Get(key)
 | 
						var code int
 | 
				
			||||||
	if err != nil || int(code.(float64)) != data.Code {
 | 
						err := h.levelDB.Get(key, &code)
 | 
				
			||||||
 | 
						if err != nil || code != data.Code {
 | 
				
			||||||
		resp.ERROR(c, "短信验证码错误")
 | 
							resp.ERROR(c, "短信验证码错误")
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ import (
 | 
				
			|||||||
	"chatplus/store"
 | 
						"chatplus/store"
 | 
				
			||||||
	"chatplus/utils"
 | 
						"chatplus/utils"
 | 
				
			||||||
	"chatplus/utils/resp"
 | 
						"chatplus/utils/resp"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/gin-gonic/gin"
 | 
						"github.com/gin-gonic/gin"
 | 
				
			||||||
@@ -20,8 +21,9 @@ type VerifyHandler struct {
 | 
				
			|||||||
	db  *store.LevelDB
 | 
						db  *store.LevelDB
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const TokenStorePrefix = "/tokens/"
 | 
					const TokenStorePrefix = "/verify/tokens/"
 | 
				
			||||||
const CodeStorePrefix = "/codes/"
 | 
					const CodeStorePrefix = "/verify/codes/"
 | 
				
			||||||
 | 
					const MobileStatPrefix = "/verify/stats/"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewVerifyHandler(app *core.AppServer, sms *service.AliYunSmsService, db *store.LevelDB) *VerifyHandler {
 | 
					func NewVerifyHandler(app *core.AppServer, sms *service.AliYunSmsService, db *store.LevelDB) *VerifyHandler {
 | 
				
			||||||
	handler := &VerifyHandler{sms: sms, db: db}
 | 
						handler := &VerifyHandler{sms: sms, db: db}
 | 
				
			||||||
@@ -34,11 +36,24 @@ type VerifyToken struct {
 | 
				
			|||||||
	Timestamp int64
 | 
						Timestamp int64
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CodeStats 验证码发送统计
 | 
				
			||||||
 | 
					type CodeStats struct {
 | 
				
			||||||
 | 
						Mobile string
 | 
				
			||||||
 | 
						Count  uint
 | 
				
			||||||
 | 
						Time   int64
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Token 生成自验证 token
 | 
					// Token 生成自验证 token
 | 
				
			||||||
func (h *VerifyHandler) Token(c *gin.Context) {
 | 
					func (h *VerifyHandler) Token(c *gin.Context) {
 | 
				
			||||||
	// 确保是通过浏览器访问
 | 
						// 如果不是通过浏览器访问,则返回错误的 token
 | 
				
			||||||
	if c.GetHeader("Sec-Fetch-Mode") != "cors" {
 | 
						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
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -85,17 +100,31 @@ func (h *VerifyHandler) SendMsg(c *gin.Context) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_, err = h.db.Get(TokenStorePrefix + token.Token)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		resp.HACKER(c)
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if time.Now().Unix()-token.Timestamp > 30 {
 | 
						if time.Now().Unix()-token.Timestamp > 30 {
 | 
				
			||||||
		resp.ERROR(c, "Token 已过期,请刷新页面重试")
 | 
							resp.ERROR(c, "Token 已过期,请刷新页面重试")
 | 
				
			||||||
		return
 | 
							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)
 | 
						code := utils.RandomNumber(6)
 | 
				
			||||||
	err = h.sms.SendVerifyCode(data.Mobile, code)
 | 
						err = h.sms.SendVerifyCode(data.Mobile, code)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -112,5 +141,10 @@ func (h *VerifyHandler) SendMsg(c *gin.Context) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 更新发送次数
 | 
				
			||||||
 | 
						stat.Count = stat.Count + 1
 | 
				
			||||||
 | 
						_ = h.db.Put(MobileStatPrefix+data.Mobile, stat)
 | 
				
			||||||
 | 
						logger.Infof("%+v", stat)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	resp.SUCCESS(c)
 | 
						resp.SUCCESS(c)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,6 @@ package store
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"chatplus/store/vo"
 | 
						"chatplus/store/vo"
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/syndtr/goleveldb/leveldb"
 | 
						"github.com/syndtr/goleveldb/leveldb"
 | 
				
			||||||
	"github.com/syndtr/goleveldb/leveldb/util"
 | 
						"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)
 | 
						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)
 | 
						bytes, err := db.driver.Get([]byte(key), nil)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var value interface{}
 | 
						return json.Unmarshal(bytes, &value)
 | 
				
			||||||
	err = json.Unmarshal(bytes, &value)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return value, nil
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (db *LevelDB) Search(prefix string) []string {
 | 
					func (db *LevelDB) Search(prefix string) []string {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,8 +17,7 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					func main() {
 | 
				
			||||||
	//testAesEncrypt()
 | 
						testAesEncrypt()
 | 
				
			||||||
	fmt.Println(utils.RandomNumber(6))
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Http client 取消操作
 | 
					// Http client 取消操作
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,7 +31,7 @@ const sendMsg = () => {
 | 
				
			|||||||
  httpGet('/api/verify/token').then(res => {
 | 
					  httpGet('/api/verify/token').then(res => {
 | 
				
			||||||
    httpPost('/api/verify/sms', {token: res.data, mobile: props.mobile}).then(() => {
 | 
					    httpPost('/api/verify/sms', {token: res.data, mobile: props.mobile}).then(() => {
 | 
				
			||||||
      ElMessage.success('短信发送成功')
 | 
					      ElMessage.success('短信发送成功')
 | 
				
			||||||
      let time = 120
 | 
					      let time = 10
 | 
				
			||||||
      btnText.value = time
 | 
					      btnText.value = time
 | 
				
			||||||
      const handler = setInterval(() => {
 | 
					      const handler = setInterval(() => {
 | 
				
			||||||
        time = time - 1
 | 
					        time = time - 1
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user