调研
网上有两种star比较多的开源库,分别是
两者star差不多,第一个是中国人写的,中文文档比较详细,所以使用第一个
初始化
把自定义的redis当作store,新建一个结构体实现cap.store接口的方法
var c *cap.Captcha
func Init(store cap.Store) {
c = cap.NewCaptcha(cap.NewDriverString(60, 200, 0, 1, 4, "1234567890qwertyuioplkjhgfdsazxcvbnm", &color.RGBA{128, 128, 128, 3}, nil, nil), store)
}
生成验证码
func Generate() (id, b64s string, err error) {
id, b64s, err = c.Generate()
if err != nil {
fmt.Println(err)
return
}
return
}
校验
func Verify(id, verifyVal string, clear bool) bool {
//防止缓存没有值,参数为空导致的校验成功的异常case
if verifyVal == "" {
log.Warn("[captcha] Verify param wrong", zap.String("id", id), zap.String("verifyVal", verifyVal))
return false
}
return c.Verify(id, verifyVal, clear)
}
自定义store
实现默认store的方法
const (
storeExp = time.Minute
)
type Re struct {
rdb *redis.Client
}
func RedisStore(redi *redis.Client) (r *Re) {
if redi == nil {
fmt.Println("redis init failed ")
return nil
}
r = &Re{}
r.rdb = redi
return r
}
func (r *Re) Set(id string, value string) error {
if r.rdb == nil {
log.Error("[captcha] redis cli nil")
return fmt.Errorf("[captcha] redis cli nil")
}
_, err := r.rdb.Set(context.Background(), id, value, storeExp).Result()
if err != nil {
log.Error("[captcha] redis set failed", zap.Error(err))
return err
}
return nil
}
// Get returns stored digits for the captcha id. Clear indicates
// whether the captcha must be deleted from the store.
func (r *Re) Get(id string, clear bool) string {
if r.rdb == nil {
log.Error("[captcha] redis cli nil")
return ""
}
res, err := r.rdb.Get(context.Background(), id).Result()
if err != nil {
log.Error("[captcha] redis get failed",zap.Error(err))
return ""
}
if clear {
_, err := r.rdb.Del(context.Background(), id).Result()
if err != nil {
//可能导致二次校验也成功
log.Error("[captcha] redis del failed",zap.Error(err))
return res
}
}
return res
}
// Verify captcha's answer directly
func (r *Re) Verify(id, answer string, clear bool) bool {
return answer == r.Get(id, clear)
}
考虑
1.要不要限制前端刷新次数,不然后端会一直往redis里面存储,只能自然过期,不过占用空间应该很小