最近研究了下开源的验证码框架dchest/captcha github地址,可以实现图片验证码(数字+运算公式),声音验证码。今天就以图片验证码为例子,做个简单demo
分析思路
根据框架源码介绍,大概可以分为三块内容
- 创建验证码
- 校验验证码
- 验证码图片获取
1.创建验证码
创建验证码函数变量代码
type CaptchaResponse struct {
CaptchaId string `json:"captchaId"`
ImageUrl string `json:"imageUrl"`
}
var GetCaptcha = func(context *gin.Context) {
baseResponse := model.NewBaseResponse()
d := struct {
CaptchaId string
}{
captcha.New(),
}
if d.CaptchaId != "" {
baseResponse.GetSuccessResponse()
var captcha model.CaptchaResponse
captcha.CaptchaId = d.CaptchaId
captcha.ImageUrl = "/show/" + d.CaptchaId + ".png"
baseResponse.Data = captcha
} else {
baseResponse.GetFailureResponse(model.SYSTEM_ERROE)
}
context.JSON(http.StatusOK, baseResponse)
}
2.校验验证码
校验验证码函数变量代码
var VerifyCaptcha = func(context *gin.Context) {
baseResponse := model.NewBaseResponse()
captchaId := context.Request.FormValue("captchaId")
value := context.Request.FormValue("value")
if captchaId == "" || value == "" {
baseResponse.GetFailureResponse(model.QUERY_PARAM_ERROR)
} else {
if captcha.VerifyString(captchaId, value) {
baseResponse.GetSuccessResponse()
baseResponse.Message = "验证成功"
} else {
baseResponse.GetFailureResponse(model.CAPTCHA_ERROR)
}
}
context.JSON(http.StatusOK, baseResponse)
}
3.验证码图片获取
dchest/captcha框架中图片获取是用的非Gin方式实现,并且Gin对文件下载支持的并不友好。想要使用Gin方式实现,得将框架源码中图片查找response代码copy一份自己实现。
func Serve(w http.ResponseWriter, r *http.Request, id, ext, lang string, download bool, width, height int) error {
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
w.Header().Set("Pragma", "no-cache")
w.Header().Set("Expires", "0")
var content bytes.Buffer
switch ext {
case ".png":
w.Header().Set("Content-Type", "image/png")
captcha.WriteImage(&content, id, width, height)
case ".wav":
w.Header().Set("Content-Type", "audio/x-wav")
captcha.WriteAudio(&content, id, lang)
default:
return captcha.ErrNotFound
}
if download {
w.Header().Set("Content-Type", "application/octet-stream")
}
http.ServeContent(w, r, id+ext, time.Time{}, bytes.NewReader(content.Bytes()))
return nil
}
func ServeHTTP(w http.ResponseWriter, r *http.Request) {
dir, file := path.Split(r.URL.Path)
ext := path.Ext(file)
id := file[:len(file)-len(ext)]
fmt.Println("file : " + file)
fmt.Println("ext : " + ext)
fmt.Println("id : " + id)
if ext == "" || id == "" {
http.NotFound(w, r)
return
}
fmt.Println("reload : " + r.FormValue("reload"))
if r.FormValue("reload") != "" {
captcha.Reload(id)
}
lang := strings.ToLower(r.FormValue("lang"))
download := path.Base(dir) == "download"
if Serve(w, r, id, ext, lang, download, captcha.StdWidth, captcha.StdHeight) == captcha.ErrNotFound {
http.NotFound(w, r)
}
从这里可以看出,加载音频验证码文件也是从这里实现的。
接下来,实现图片加载函数变量
var GetCaptchaPng = func(context *gin.Context) {
source := context.Param("source")
logrus.Info("GetCaptchaPng : " + source)
recaptcha.ServeHTTP(context.Writer, context.Request)
}
Gin部分
验证码逻辑已写完,接下来用Gin将代码跑起来
func main() {
ginRouter := gin.New()
ginRouter.GET("/getCaptcha", controller.GetCaptcha)
ginRouter.GET("/verifyCaptcha", controller.VerifyCaptcha)
ginRouter.GET("/show/:source", controller.GetCaptchaPng)
ginRouter.Run(":8080")
}
测试效果
- 使用postman调用获取验证码
得到返回结果
{
"code": 1000,
"message": "success",
"data": {
"captchaId": "VaK1byBtI8TUh8KP6ZrO",
"imageUrl": "/show/VaK1byBtI8TUh8KP6ZrO.png"
}
}
其中 captchaId就是验证码的Id(非value)
imageUrl就是生成的验证码图片路径,保存在服务器本地
- 获取验证码图片
加上Host,访问图片地址http://192.168.1.2:8080/show/VaK1byBtI8TUh8KP6ZrO.png
得到图片效果如下
如想要刷新图片验证码,则只需要将url参数加上&reload=true
http://192.168.1.2:8080/show/VaK1byBtI8TUh8KP6ZrO.png&reload=true
这样会将新生成的验证码value替换覆盖原来的。
- 使用postman调用验证验证码
传入captchaId和图片中验证码的值
得到结果如下
{
"code": 1000,
"message": "验证成功"
}
注意: 验证码验证成功后,缓存图片即被清除
最后
附上完整代码 github地址
如加星,万分感激.