最近研究了下開源的驗(yàn)證碼框架dchest/captcha github地址,可以實(shí)現(xiàn)圖片驗(yàn)證碼(數(shù)字+運(yùn)算公式),聲音驗(yàn)證碼。今天就以圖片驗(yàn)證碼為例子,做個(gè)簡單demo
分析思路

驗(yàn)證碼流程圖.jpg
根據(jù)框架源碼介紹,大概可以分為三塊內(nèi)容
- 創(chuàng)建驗(yàn)證碼
- 校驗(yàn)驗(yàn)證碼
- 驗(yàn)證碼圖片獲取
1.創(chuàng)建驗(yàn)證碼
創(chuàng)建驗(yàn)證碼函數(shù)變量代碼
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.校驗(yàn)驗(yàn)證碼
校驗(yàn)驗(yàn)證碼函數(shù)變量代碼
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 = "驗(yàn)證成功"
} else {
baseResponse.GetFailureResponse(model.CAPTCHA_ERROR)
}
}
context.JSON(http.StatusOK, baseResponse)
}
3.驗(yàn)證碼圖片獲取
dchest/captcha框架中圖片獲取是用的非Gin方式實(shí)現(xiàn),并且Gin對文件下載支持的并不友好。想要使用Gin方式實(shí)現(xiàn),得將框架源碼中圖片查找response代碼copy一份自己實(shí)現(xiàn)。
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)
}
從這里可以看出,加載音頻驗(yàn)證碼文件也是從這里實(shí)現(xiàn)的。
接下來,實(shí)現(xiàn)圖片加載函數(shù)變量
var GetCaptchaPng = func(context *gin.Context) {
source := context.Param("source")
logrus.Info("GetCaptchaPng : " + source)
recaptcha.ServeHTTP(context.Writer, context.Request)
}
Gin部分
驗(yàn)證碼邏輯已寫完,接下來用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調(diào)用獲取驗(yàn)證碼
得到返回結(jié)果
{
"code": 1000,
"message": "success",
"data": {
"captchaId": "VaK1byBtI8TUh8KP6ZrO",
"imageUrl": "/show/VaK1byBtI8TUh8KP6ZrO.png"
}
}
其中 captchaId就是驗(yàn)證碼的Id(非value)
imageUrl就是生成的驗(yàn)證碼圖片路徑,保存在服務(wù)器本地
- 獲取驗(yàn)證碼圖片
加上Host,訪問圖片地址http://192.168.1.2:8080/show/VaK1byBtI8TUh8KP6ZrO.png
得到圖片效果如下
驗(yàn)證碼圖片.jpg
如想要刷新圖片驗(yàn)證碼,則只需要將url參數(shù)加上&reload=true
http://192.168.1.2:8080/show/VaK1byBtI8TUh8KP6ZrO.png&reload=true
這樣會將新生成的驗(yàn)證碼value替換覆蓋原來的。
- 使用postman調(diào)用驗(yàn)證驗(yàn)證碼
傳入captchaId和圖片中驗(yàn)證碼的值
得到結(jié)果如下
{
"code": 1000,
"message": "驗(yàn)證成功"
}
注意: 驗(yàn)證碼驗(yàn)證成功后,緩存圖片即被清除
最后
附上完整代碼 github地址
如加星,萬分感激.
