go项目中使用redis解决分布式的图形验证

710 阅读2分钟

在gin框架中实现图片验证

这里使用的库是"github.com/mojocn/base64Captcha",可以在CaptMake()中去修改来达到自己想要的验证码的样式

package main

import (
   "demo/models"
   "fmt"
   "github.com/gin-gonic/gin"
   "net/http"
)

type test struct {
   id string `json:"id"`
   b64s string `json:"b64s"`
}

func main() {
   //Default返回一个默认的路由引擎
   r := gin.Default()
   id,b64s,err := models.CaptMake()
   if err != nil {
      fmt.Println(err)
   }
   r.GET("/test", func(c *gin.Context) {
      c.JSON(http.StatusOK,gin.H{
         "id" : id,
         "testId" : b64s,
      })
   })
   r.POST("/testPost", func(c *gin.Context) {
      var t = new(test)
      c.ShouldBindJSON(t)
      if flag := models.CaptVerify(t.id,t.b64s); flag == true {
         fmt.Println("验证验证码成功")
      } else {
         fmt.Println("验证验证码失败") }

   })
   r.Run()
}
package models

import (
   "github.com/mojocn/base64Captcha"
   "image/color"
)


var store = base64Captcha.DefaultMemStore

//生成验证码
func CaptMake() (id, b64s string, err error) {
   var driver base64Captcha.Driver
   // 配置验证码信息
   driverString := base64Captcha.DriverString{
      Height: 40,
      Width: 100,
      NoiseCount: 0,
      ShowLineOptions: 2 | 4,
      Length: 4,
      Source: "1234567890qwertyuioplkjhgfdsazxcvbnm", BgColor: &color.RGBA{
         R: 3, G: 102, B: 214, A: 125,
      },
      Fonts: []string{"wqy-microhei.ttc"}, }
   //ConvertFonts 按名称加载字体
   driver = driverString.ConvertFonts()
   //创建 Captcha
   captcha := base64Captcha.NewCaptcha(driver, store) //Generate 生成随机 id、base64 图像字符串
   lid, lb64s, lerr := captcha.Generate()
   return lid, lb64s, lerr

}


//验证 captcha 是否正确
func CaptVerify(id string, capt string) bool {
   if store.Verify(id, capt, false) {
      return true
   } else {
      return false
   }
}

解决分布式的验证问题

截屏2022-01-18 下午5.21.39.png

在分布式的场景中,可能我们在生成图形验证码和最终验证验证码的机器不是同一个,这个时候就会产生错误。

为了解决这个问题,我们可以使用redis,将每一次从服务端得到的数据存放到redis中,然后每一次验证的时候直接到redis中去验证。

为了减少内存的压力,我们可以在每一次验证完数据的时候将redis存放的数据删除。 这几个seet之类的方法是为了实现store接口,set是自动调用的。

package models

import (
   "context"
   "fmt"
   "github.com/go-redis/redis/v8"
   "github.com/mojocn/base64Captcha"
   "image/color"
   "time"
)


var store base64Captcha.Store = RedisStore{}

//生成验证码
func CaptMake() (id, b64s string, err error) {
   var driver base64Captcha.Driver
   // 配置验证码信息
   driverString := base64Captcha.DriverString{
      Height: 40,
      Width: 100,
      NoiseCount: 0,
      ShowLineOptions: 2 | 4,
      Length: 4,
      Source: "1234567890qwertyuioplkjhgfdsazxcvbnm", BgColor: &color.RGBA{
         R: 3, G: 102, B: 214, A: 125,
      },
      Fonts: []string{"wqy-microhei.ttc"}, }
   //ConvertFonts 按名称加载字体
   driver = driverString.ConvertFonts()
   //创建 Captcha
   captcha := base64Captcha.NewCaptcha(driver, store) //Generate 生成随机 id、base64 图像字符串
   lid, lb64s, lerr := captcha.Generate()
   return lid, lb64s, lerr

}


//验证 captcha 是否正确
func CaptVerify(id string, capt string) bool {
   if store.Verify(id, capt, false) {
      return true
   } else {
      return false
   }
}


var RedisDb *redis.Client

func init() {
   var ctx = context.Background()
   RedisDb = redis.NewClient(&redis.Options{
      Addr: "127.0.0.1:6379", Password: "", // no password set DB: 0, // use default DB
   })
   _, err := RedisDb.Ping(ctx).Result()
   if err != nil {
      println(err)
   }
}
var ctx = context.Background()


const CAPTCHA = "captcha:"
type RedisStore struct {
}
//实现设置 captcha 的方法
func (r RedisStore) Set(id string, value string) error {
   key := CAPTCHA + id
   err := RedisDb.Set(ctx, key, value, time.Minute*2).Err()
   return err
}

//实现获取 captcha 的方法
func (r RedisStore) Get(id string, clear bool) string {
   key := CAPTCHA + id
   val, err := RedisDb.Get(ctx, key).Result() ;if err != nil {
      fmt.Println(err)
      return "" }
   if clear {
      err := RedisDb.Del(ctx, key).Err(); if err != nil {
         fmt.Println(err)
         return "" }
   }
   return val }
//实现验证 captcha 的方法
func (r RedisStore) Verify(id, answer string, clear bool) bool {
   v := RedisStore{}.Get(id, clear)
   fmt.Println("key:"+id+";value:"+v+";answer:"+answer)
   return v == answer
}