我们用GO玩一下验证码
[TOC]
我们用GO玩一下验证码
嗨,我是小魔童哪吒,咱们上次分享的GO 中 defer
的实现原理,再来回顾一下吧
- 分享了defer是什么
- 简单示意了栈和队列
- defer的数据结构和实现原理,具体的源码展示
- GO 中
defer
的 3 条规则
defer
实现原理还有点兴趣的话,欢迎查看文章 GO 中 defer的实现原理今天我们来分享一些使用
GO
实现小案例,咱们边玩边成长文章图片
GO 的验证码介绍 我们平时使用到的验证码大致分为这几种,咱们梳理一下:
- 传统输入的形式
- 输入类型的图形验证码
- 纯行为验证码
- 图标选择与行为辅助的验证码
- 点击式的图文验证与行为辅助
- 智能验证码
GO 验证码案例 我们今天就来玩一玩第一种,使用最多的一种验证码吧
会使用 GO 的这个验证码库来完成,
github.com/dchest/captcha
若我们向
C/C++
一样,将很多的底层处理都是我们自己来封装来实现的话,那还是挺累人的,GO 这一点确实蛮好,有很多使用的包,咱们在使用之余,也可以站在巨人的肩膀,学习源码中的实现方式,学习大佬们的设计思想。文章图片
安装
captcha
库大家使用如下命令就可以下载下来使用
go get github.com/dchest/captcha
当我们在
GOLAND
中用到 captcha
库的时候,咱们可以看看源码目录源码目录
文章图片
- 有源码的具体使用案例
- 具体的示例图片
- 相关音频处理的实现
- 验证码处理的实现
- 图片处理的实现
- 随机数处理的实现方式
- 等等...
文章图片
这个库目前支持的音频有 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 中看到这个,就有点像做字库解析 和 嵌入式里面的数据解析了
文章图片
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,
...
},
开始案例的演示
文章图片
my_captcha.html 实现如下
【我们用GO玩一下验证码】暂时关于音频的语言,就写了2种语言
- 英文
- 中文
GO 简单制作验证码案例 input{
margin-top: 30px;
}
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)
}
验证码实际效果
文章图片
点击播放音频验证码的时候,可以看到这样的效果
文章图片
该音频,会根据我们选择语言,来播放不同的语音,读取图片上的数字
文章图片
总结
- 验证码种类梳理
- 验证码库的安装
- 验证码库的源码介绍
- 实操,编码
- 验证码效果展示
文章图片
好了,本次就到这里,下一次 如何使用GOLANG发送邮件
技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。
我是小魔童哪吒,欢迎点赞关注收藏,下次见~
推荐阅读
- Docker应用:容器间通信与Mariadb数据库主从复制
- 第三节|第三节 快乐和幸福(12)
- 这辈子我们都不要再联系了
- JS中的各种宽高度定义及其应用
- 由浅入深理解AOP
- 游戏IP(立足于玩家情感的粉丝经济)
- 诗歌:|诗歌: 《让我们举起世界杯,干了!》
- 我们重新了解付费。
- 【译】20个更有效地使用谷歌搜索的技巧
- 那件我们忽略的小事叫感恩