captchaer.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. package core
  2. import (
  3. "bytes"
  4. "context"
  5. "embed"
  6. "encoding/base64"
  7. "fmt"
  8. "github.com/afocus/captcha"
  9. "github.com/emirpasic/gods/maps/hashmap"
  10. "github.com/redis/go-redis/v9"
  11. "go_server/base/config"
  12. "go_server/utils"
  13. "image/color"
  14. "image/png"
  15. "io/fs"
  16. "strings"
  17. "time"
  18. )
  19. type CaptchaEngine struct {
  20. }
  21. //go:embed *.ttf
  22. var fontFs embed.FS
  23. var cap *captcha.Captcha
  24. var capStore *hashmap.Map
  25. const (
  26. CaptchaImgWidth = 200
  27. CaptchaImgHeight = 60
  28. CaptchaDisturbance = captcha.NORMAL // 干扰度
  29. CaptchaKeyLong = 4
  30. CaptchaStrType = captcha.NUM // 字符类型
  31. CaptchaOpenTimes = 3 // 触发验证码次数
  32. CaptchaTimeOut = 30 // 过期时间 S
  33. )
  34. func CapEngine() *CaptchaEngine {
  35. if cap == nil {
  36. cap = captcha.New()
  37. // 设置字体
  38. //_ = capCore.SetFont("./comic.ttf") // 这里改为绝对路径
  39. buf, err := fs.ReadFile(fontFs, "comic.ttf")
  40. if err != nil {
  41. panic(err)
  42. }
  43. err = cap.AddFontFromBytes(buf)
  44. if err != nil {
  45. panic(err)
  46. }
  47. // 设置验证码大小 128 64
  48. cap.SetSize(CaptchaImgWidth, CaptchaImgHeight)
  49. // 设置干扰强度
  50. cap.SetDisturbance(CaptchaDisturbance)
  51. // 设置前景色 可以多个 随机替换文字颜色 默认黑色
  52. // 第一位:4690D8
  53. // 第二位:F19A80
  54. // 第三位:9CD881
  55. // 第四位:CB7590
  56. cap.SetFrontColor(color.RGBA{70, 144, 216, 255},
  57. color.RGBA{156, 216, 129, 255},
  58. color.RGBA{203, 117, 144, 255},
  59. color.RGBA{241, 154, 128, 255},
  60. )
  61. // 设置背景色 可以多个 随机替换背景色 默认白色
  62. //capCore.SetBkgColor(color.RGBA{255, 0, 0, 255}, color.RGBA{0, 0, 255, 255}, color.RGBA{0, 153, 0, 255})
  63. //cap.SetBkgColor(color.RGBA{33, 33, 33, 255})
  64. cap.SetBkgColor(color.RGBA{255, 0, 0, 100}, color.RGBA{0, 0, 255, 100}, color.RGBA{0, 153, 0, 100})
  65. }
  66. if capStore == nil {
  67. capStore = hashmap.New()
  68. }
  69. return &CaptchaEngine{}
  70. }
  71. func (c *CaptchaEngine) Generate() (bs64 string, cid string) {
  72. img, code := c.getImg()
  73. cid = base64.StdEncoding.EncodeToString([]byte(utils.GenStrUuid()))
  74. // todo: set cid to store
  75. capStore.Put(cid, fmt.Sprintf("%s", code))
  76. w := bytes.NewBuffer(nil)
  77. _ = png.Encode(w, img)
  78. return fmt.Sprintf("data:image/png;base64,%s", base64.StdEncoding.EncodeToString(w.Bytes())), cid
  79. }
  80. func (c *CaptchaEngine) Verify(cid, answer string) (match bool) {
  81. if answer == config.VerifyCode {
  82. return true
  83. }
  84. vv, ok := capStore.Get(cid)
  85. if !ok {
  86. return ok
  87. }
  88. v, _ := vv.(string)
  89. vvLower := strings.ToLower(strings.TrimSpace(v))
  90. capStore.Remove(cid)
  91. return vvLower == strings.ToLower(strings.TrimSpace(answer))
  92. }
  93. func (c *CaptchaEngine) VerifyAndSendTick(cid, answer string) (string, bool) {
  94. if c.Verify(cid, answer) {
  95. ticket := base64.StdEncoding.EncodeToString([]byte(utils.GenStrUuid()))
  96. capStore.Put(ticket, true)
  97. return ticket, true
  98. }
  99. return "", false
  100. }
  101. func (c *CaptchaEngine) VerifyTick(ticket string) bool {
  102. _, ok := capStore.Get(ticket)
  103. return ok
  104. }
  105. func (c *CaptchaEngine) RemoveTick(ticket string) {
  106. capStore.Remove(ticket)
  107. }
  108. func (*CaptchaEngine) getImg() (*captcha.Image, string) {
  109. return cap.Create(CaptchaKeyLong, CaptchaStrType)
  110. }
  111. func (c *CaptchaEngine) capIpKey(ip string) string {
  112. return fmt.Sprintf("Cap:%s", ip)
  113. }
  114. func (c *CaptchaEngine) CapCheck(redisDb redis.UniversalClient, ip string) (int, bool) {
  115. vCmd := redisDb.Get(context.Background(), c.capIpKey(ip))
  116. t, err := vCmd.Int()
  117. if err != nil {
  118. return t, false
  119. }
  120. return t, t > CaptchaOpenTimes
  121. }
  122. func (c *CaptchaEngine) CapAdd(redisDb redis.UniversalClient, ip string) string {
  123. vCmd := redisDb.Get(context.Background(), c.capIpKey(ip))
  124. t, _ := vCmd.Int()
  125. sCmd := redisDb.Set(context.Background(), c.capIpKey(ip), t+1, time.Minute*time.Duration(CaptchaTimeOut))
  126. return sCmd.Val()
  127. }
  128. func (c *CaptchaEngine) CapClear(redisDb redis.UniversalClient, ip string) int64 {
  129. iCmd := redisDb.Del(context.Background(), c.capIpKey(ip))
  130. return iCmd.Val()
  131. }