我们用GO玩一下验证码

[TOC]
我们用GO玩一下验证码 嗨,我是小魔童哪吒,咱们上次分享的GO 中 defer 的实现原理,再来回顾一下吧

  • 分享了defer是什么
  • 简单示意了栈和队列
  • defer的数据结构和实现原理,具体的源码展示
  • GO 中defer的 3 条规则
要是对 GO 中 defer 实现原理还有点兴趣的话,欢迎查看文章 GO 中 defer的实现原理
今天我们来分享一些使用 GO 实现小案例,咱们边玩边成长
我们用GO玩一下验证码
文章图片

GO 的验证码介绍 我们平时使用到的验证码大致分为这几种,咱们梳理一下:
  • 传统输入的形式
输入图片上的数字,文字,字母等等
  • 输入类型的图形验证码
这个主要是来打广告的
  • 纯行为验证码
例如,按照提示滑动等等
  • 图标选择与行为辅助的验证码
例如咱们买火车票的时候验证码,各种图标让你选
  • 点击式的图文验证与行为辅助
例如某宝的验证码
  • 智能验证码
例如,点触智能验证码
GO 验证码案例 我们今天就来玩一玩第一种,使用最多的一种验证码吧
会使用 GO 的这个验证码库来完成,github.com/dchest/captcha
若我们向C/C++一样,将很多的底层处理都是我们自己来封装来实现的话,那还是挺累人的,GO 这一点确实蛮好,有很多使用的包,咱们在使用之余,也可以站在巨人的肩膀,学习源码中的实现方式,学习大佬们的设计思想。
我们用GO玩一下验证码
文章图片

安装captcha
大家使用如下命令就可以下载下来使用
go get github.com/dchest/captcha

当我们在GOLAND 中用到 captcha库的时候,咱们可以看看源码目录
源码目录
我们用GO玩一下验证码
文章图片

  • 有源码的具体使用案例
  • 具体的示例图片
  • 相关音频处理的实现
  • 验证码处理的实现
  • 图片处理的实现
  • 随机数处理的实现方式
  • 等等...
支持的语言
我们用GO玩一下验证码
文章图片

这个库目前支持的音频有 4 种语言:
  • 英文
  • 中文
  • 俄文
  • 日文
验证码默认参数
库中验证码的大小默认是 宽 240 px,高 80 px
在源码中的 image.go
const ( // Standard width and height of a captcha image. StdWidth= 240 StdHeight = 80 // Maximum absolute skew factor of a single digit. maxSkew = 0.7 // Number of background circles. circleCount = 20 )type Image struct { *image.Paletted numWidthint numHeight int dotSizeint rngsiprng }

随机数包含的字符
如下是验证码id中允许的字符 ,可以在源码中看到
源码包中的 random.go
// idChars are characters allowed in captcha id. var idChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")

关于音频的处理
在源码的 sounds.go文件
目前对于音频只支持 4 种语言,"en", "ja", "ru", "zh".
/ NewAudio returns a new audio captcha with the given digits, where each digit // must be in range 0-9. Digits are pronounced in the given language. If there // are no sounds for the given language, English is used. // // Possible values for lang are "en", "ja", "ru", "zh". func NewAudio(id string, digits []byte, lang string) *Audio { a := new(Audio)// Initialize PRNG. a.rng.Seed(deriveSeed(audioSeedPurpose, id, digits))if sounds, ok := digitSounds[lang]; ok { a.digitSounds = sounds } else { a.digitSounds = digitSounds["en"] } numsnd := make([][]byte, len(digits)) nsdur := 0 for i, n := range digits { snd := a.randomizedDigitSound(n) nsdur += len(snd) numsnd[i] = snd } // Random intervals between digits (including beginning). intervals := make([]int, len(digits)+1) intdur := 0 for i := range intervals { dur := a.rng.Int(sampleRate, sampleRate*3) // 1 to 3 seconds intdur += dur intervals[i] = dur } // Generate background sound. bg := a.makeBackgroundSound(a.longestDigitSndLen()*len(digits) + intdur) // Create buffer and write audio to it. sil := makeSilence(sampleRate / 5) bufcap := 3*len(beepSound) + 2*len(sil) + len(bg) + len(endingBeepSound) a.body = bytes.NewBuffer(make([]byte, 0, bufcap)) // Write prelude, three beeps. a.body.Write(beepSound) a.body.Write(sil) a.body.Write(beepSound) a.body.Write(sil) a.body.Write(beepSound) // Write digits. pos := intervals[0] for i, v := range numsnd { mixSound(bg[pos:], v) pos += len(v) + intervals[i+1] } a.body.Write(bg) // Write ending (one beep). a.body.Write(endingBeepSound) return a }

其中关于语言的数据在digitSounds map 中
看到这个,就有点像做字库解析 和 嵌入式里面的数据解析了
我们用GO玩一下验证码
文章图片

var digitSounds = map[string][][]byte{ "en": [][]byte{ { // 0 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, ... }, "ru": [][]byte{ { // 0 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, ... }, "zh": [][]byte{ { // 0 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, ... }, "ja": [][]byte{ { // 0 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x83, ... },

开始案例的演示
我们用GO玩一下验证码
文章图片

my_captcha.html 实现如下
【我们用GO玩一下验证码】暂时关于音频的语言,就写了2种语言
  • 英文
  • 中文
GO 简单制作验证码案例input{ margin-top: 30px; }
请输入你在下面的图片中看到的数字:
我们用GO玩一下验证码
文章图片

重新加载|播放音频验证码You browser doesn't support audio. 下载文件 to play it in the external player.

main.go
  • 展示验证码
  • 处理验证码,结果展示
  • 重载验证码
  • 播放验证码音频
package mainimport ( "github.com/dchest/captcha" "io" "io/ioutil" "log" "net/http" "text/template" )const filePath = "./my_captcha.html" // 读取 html 文件 func readHtml() string { var bytes []byte var err error if bytes, err = ioutil.ReadFile(filePath); err != nil { log.Fatalf("ioutil.ReadFile error filePath =%s , err :"+filePath, err) return "" }return string(bytes) }// 读取html 文件,转成template.Template 指针 var formTemplate = template.Must(template.New("myCaptcha").Parse(readHtml()))// 显示验证码 func showCaptcha(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/" { http.NotFound(w, r) return } d := struct { CaptchaId string }{ captcha.New(), } // Execute将解析后的模板应用到指定的数据对象,并将输出写入wr if err := formTemplate.Execute(w, &d); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } }// 处理验证码,跳转结果页面 func resultPage(w http.ResponseWriter, r *http.Request) {w.Header().Set("Content-Type", "text/html; charset=utf-8")if !captcha.VerifyString(r.FormValue("captchaId"), r.FormValue("captchaSolution")) { io.WriteString(w, "错误的验证码,请重新输入\n") } else { io.WriteString(w, "验证吗正确,你很棒哦!!\n") } io.WriteString(w, "
再试一下") }func main() {// 简单设置log参数 log.SetFlags(log.Lshortfile | log.LstdFlags)http.HandleFunc("/", showCaptcha) http.HandleFunc("/processCapcha", resultPage)http.Handle("/captcha/", captcha.Server(captcha.StdWidth, captcha.StdHeight))log.Println("starting server : 8888")if err := http.ListenAndServe("localhost:8888", nil); err != nil { log.Fatal(err) } }

上述代码的宽高 是这样的
StdWidth= 240 StdHeight = 80

上述 HandleFunc 的回调函数是这个样子的,之前介绍 gin 的时候有分享过, 可以回头看看 文章 来我们一起探究一下net/http 的代码流程
// HandleFunc registers the handler function for the given pattern // in the DefaultServeMux. // The documentation for ServeMux explains how patterns are matched. func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { DefaultServeMux.HandleFunc(pattern, handler) }

验证码实际效果 我们用GO玩一下验证码
文章图片

点击播放音频验证码的时候,可以看到这样的效果
我们用GO玩一下验证码
文章图片

该音频,会根据我们选择语言,来播放不同的语音,读取图片上的数字
我们用GO玩一下验证码
文章图片

总结
  • 验证码种类梳理
  • 验证码库的安装
  • 验证码库的源码介绍
  • 实操,编码
  • 验证码效果展示
欢迎点赞,关注,收藏 朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力
我们用GO玩一下验证码
文章图片

好了,本次就到这里,下一次 如何使用GOLANG发送邮件
技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。
我是小魔童哪吒,欢迎点赞关注收藏,下次见~

    推荐阅读