依赖的包
go get -u github.com/mojocn/base64Captcha
文档地址
https://mojotv.cn/go/refactor-base64-captcha
DEMO展示地址,按F12查看参数及返回信息
https://captcha.mojotv.cn/
刚开始运行的时候出现报错
invalid memory address or nil pointer dereference goroutine
the demo main.go must run with the frontend html file , otherwise there is no HTTP-Request-JSON-Config-Body param being POST to the go server and that makes the golang-captcha config
is not fully initialized
其实是参数传递问题,于是参考DEMO网站使用如下参数
采用 body raw 的方式传递json串
{"ShowLineOptions":["4","2","8"],"CaptchaType":"string","Id":"1ENJhuUtbyvCQozSQmE2","VerifyValue":"","DriverAudio":{"Length":6,"Language":"zh"},"DriverString":{"Height":60,"Width":245,"ShowLineOptions":14,"NoiseCount":0,"Source":"1234567890","Length":4,"Fonts":["ApothecaryFont.ttf","DeborahFancyDress.ttf","Flim-Flam.ttf","wqy-microhei.ttc"],"BgColor":{"R":0,"G":0,"B":0,"A":0}},"DriverMath":{"Height":60,"Width":240,"ShowLineOptions":14,"NoiseCount":0,"Length":6,"Fonts":["wqy-microhei.ttc"],"BgColor":{"R":0,"G":0,"B":0,"A":0}},"DriverChinese":{"Height":60,"Width":320,"ShowLineOptions":0,"NoiseCount":0,"Source":"设想,你在,处理,消费者,的音,频输,出音,频可,能无,论什,么都,没有,任何,输出,或者,它可,能是,单声道,立体声,或是,环绕立,体声的,,不想要,的值","Length":2,"Fonts":["wqy-microhei.ttc"],"BgColor":{"R":125,"G":125,"B":0,"A":118}},"DriverDigit":{"Height":80,"Width":240,"Length":5,"MaxSkew":0.7,"DotCount":80}}
选择数字验证码 digital
{"ShowLineOptions":["4","2","8"],"CaptchaType":"digit","Id":"vzFYDhJTKtFYgBQz6Jo4","VerifyValue":"","DriverAudio":{"Length":6,"Language":"zh"},"DriverString":{"Height":60,"Width":245,"ShowLineOptions":14,"NoiseCount":0,"Source":"1234567890","Length":4,"Fonts":["ApothecaryFont.ttf","DeborahFancyDress.ttf","Flim-Flam.ttf","wqy-microhei.ttc"],"BgColor":{"R":0,"G":0,"B":0,"A":0}},"DriverMath":{"Height":60,"Width":240,"ShowLineOptions":14,"NoiseCount":0,"Length":6,"Fonts":["wqy-microhei.ttc"],"BgColor":{"R":0,"G":0,"B":0,"A":0}},"DriverChinese":{"Height":60,"Width":320,"ShowLineOptions":0,"NoiseCount":0,"Source":"设想,你在,处理,消费者,的音,频输,出音,频可,能无,论什,么都,没有,任何,输出,或者,它可,能是,单声道,立体声,或是,环绕立,体声的,,不想要,的值","Length":2,"Fonts":["wqy-microhei.ttc"],"BgColor":{"R":125,"G":125,"B":0,"A":118}},"DriverDigit":{"Height":80,"Width":240,"Length":4,"MaxSkew":0.7,"DotCount":80}}
精简后
{"CaptchaType":"digit","Id":"vzFYDhJTKtFYgBQz6Jo4","VerifyValue":"","DriverDigit":{"Height":80,"Width":240,"Length":4,"MaxSkew":0.7,"DotCount":80}}
接下来对验证码的使用做一个封装,方便调用。
1、使用redis驱动存储验证码。
2、只使用数组验证码。
3、使用带有用户标识的key代替默认的随机的key来存储验证码。
captcha.go 文件
package captcha
import (
"math/rand"
"time"
"github.com/mojocn/base64Captcha"
)
func init() {
rand.Seed(time.Now().UnixNano())
}
type configJsonBody struct {
Id string
CaptchaType string
VerifyValue string
DriverAudio *base64Captcha.DriverAudio
DriverString *base64Captcha.DriverString
DriverChinese *base64Captcha.DriverChinese
DriverMath *base64Captcha.DriverMath
DriverDigit *base64Captcha.DriverDigit
}
var store = RedisStore{}
//var store = base64Captcha.DefaultMemStore
// 使用 digit
// key 为用户标识,比如手机号,token, openid等
func Generate(key string) (id string, b64s string, err error) {
//parse request parameters
param := configJsonBody{
Id: "",
CaptchaType: "digit",
VerifyValue: "",
DriverDigit: &base64Captcha.DriverDigit{
Height: 80,
Width: 240,
Length: 4,
MaxSkew: 0.7,
DotCount: 80,
},
}
var driver base64Captcha.Driver
//create base64 encoding captcha
switch param.CaptchaType {
case "audio":
driver = param.DriverAudio
case "string":
driver = param.DriverString.ConvertFonts()
case "math":
driver = param.DriverMath.ConvertFonts()
case "chinese":
driver = param.DriverChinese.ConvertFonts()
default:
driver = param.DriverDigit
}
c := base64Captcha.NewCaptcha(driver, store)
// 默认的方式下,id是随机生产的,现在改成定制的id
//id, b64s, err := c.Generate()
id, content, answer := c.Driver.GenerateIdQuestionAnswer()
item, err := c.Driver.DrawCaptcha(content)
if err != nil {
return "", "", err
}
// 使用key代替id来存储验证码
c.Store.Set(key, answer)
b64s = item.EncodeB64string()
return id, b64s, err
}
func Verify(id string, VerifyValue string) (res bool) {
//parse request json body
param := configJsonBody{
Id: id,
CaptchaType: "digit",
VerifyValue: VerifyValue,
DriverDigit: &base64Captcha.DriverDigit{
Height: 80,
Width: 240,
Length: 4,
MaxSkew: 0.7,
DotCount: 80,
},
}
//verify the captcha
return store.Verify(param.Id, param.VerifyValue, true)
}
RedisStore.go 文件
package captcha
import (
"strconv"
"voteapi/pkg/gredis"
)
const CAPTCHA = "captcha:"
type RedisStore struct {
}
// 存储的是 "8926" 而不是 8926,需要转换一下
func (r RedisStore) Set(id string, value string) {
v ,_ := strconv.Atoi(value)
gredis.Set(CAPTCHA + id, v, 180)
}
func (r RedisStore) Get(id string, clear bool) string {
key := CAPTCHA + id
re, err := gredis.Get(key)
if err != nil {
return ""
}
if clear {
gredis.Delete(key)
}
return string(re)
}
func (r RedisStore) Verify(id, answer string, clear bool) bool {
v := RedisStore{}.Get(id, clear)
return v == answer
}
调用验证码
func Captcha(c *gin.Context) {
key := c.DefaultQuery("key", "")
if key == "" {
response.JsonResponseError(c, "参数错误")
return
}
id, b64s, err := captcha.Generate(util.Md5(key))
if err != nil {
response.JsonResponseError(c, err.Error())
return
}
body := make(map[string]interface{})
body["id"] = id
body["b64s"] = b64s
response.JsonResponseSuccess(c, body)
}
校验验证码
if !captcha.Verify(captchaKey, verifyCode) {
return votedArr, errors.New("验证码校验失败")
}