go语言之生成验证码
golang中实现验证码的库有很多,本例子中以base64Captcha来实现生成图片验证码,效果如图:

图片验证码依赖库地址为:
go get github.com/mojocn/base64Captcha
实现验证码的主要步骤如下:
创建图片验证码存储对象
创建图片验证码对象有两种方式,一种是默认对象,一种是自定义对象
1、创建默认对象
使用DefaultMemStore 创建的对象,存储的验证码为 10240 个,过期时间为 10分钟,方法如下:
var captchaObj = base64Captcha.DefaultMemStore
2、创建自定义对象
自定义对象可以更改验证码存储上限,并可以自定义过期时间,如下:
var captchaObj = base64Captcha.NewMemoryStore(20000, 3*time.Minute)
配置各种类型的图片验证码
1、配置图形算术验证码,如下:
func mathConfig() *base64Captcha.DriverMath {
mathType := &base64Captcha.DriverMath{
Height: 50,
Width: 100,
NoiseCount: 0,
ShowLineOptions: base64Captcha.OptionShowHollowLine,
BgColor: &color.RGBA{
R: 40,
G: 30,
B: 89,
A: 29,
},
Fonts: nil,
}
return mathType
}
2、配置图形数字验证码,如下:
func digitConfig() *base64Captcha.DriverDigit {
digitType := &base64Captcha.DriverDigit{
Height: 50,
Width: 100,
Length: 5,
MaxSkew: 0.45,
DotCount: 10, //干扰线
}
return digitType
}
3、配置图形字符串验证码,如下:
func stringConfig() *base64Captcha.DriverString {
stringType := &base64Captcha.DriverString{
Height: 100,
Width: 100,
NoiseCount: 0,
ShowLineOptions: base64Captcha.OptionShowHollowLine | base64Captcha.OptionShowSlimeLine,
Length: 4,
Source: "helloworldchinashenzhen93567210guagndong9",
BgColor: &color.RGBA{
R: 40,
G: 30,
B: 89,
A: 29,
},
Fonts: nil,
}
return stringType
}
4、配置图形汉字验证码,如下:
func chineseConfig() *base64Captcha.DriverChinese {
chineseType := &base64Captcha.DriverChinese{
Height: 50,
Width: 500,
NoiseCount: 0,
ShowLineOptions: base64Captcha.OptionShowSlimeLine,
Length: 2,
Source: "中国,广东,深圳市,宝安区,南山区,福田区,万里路,福永",
BgColor: &color.RGBA{
R: 40,
G: 30,
B: 89,
A: 29,
},
Fonts: nil,
}
return chineseType
}
5、配置图形化数字音频验证码,如下:
func autoConfig() *base64Captcha.DriverAudio {
chineseType := &base64Captcha.DriverAudio{
Length: 4,
Language: "zh",
}
return chineseType
}
创建图片验证码
func CreateCode() (string, string, error) {
var driver base64Captcha.Driver
switch viper.GetString("code.captcha_type") {
case "audio":
driver = autoConfig()
case "string":
driver = stringConfig()
case "math":
driver = mathConfig()
case "chinese":
driver = chineseConfig()
case "digit":
driver = digitConfig()
}
if driver == nil {
panic("请在yaml文件中配置验证码类型")
}
// 创建验证码并传入创建的类型的配置,以及存储的对象
c := base64Captcha.NewCaptcha(driver, captchaObj)
id, b64s, err := c.Generate()
return id, b64s, err
}
校验验证码
func VerifyCaptcha(id, VerifyValue string) bool {
return captchaObj.Verify(id, VerifyValue, true)
}
- Verify()第三个参数为 true 时,校验传入的id 验证码,校验完后ID对应验证码会在内存中删除
- Verify()第三个参数为 true 时,校验传入的id 验证码,校验完后ID对应验证码不会在内存中删除
获取验证码
这里获取的是服务端生成的验证码的答案,比如你生成的算术验证码为1+2,那么这里获取的就是3
func GetCodeAnswer(codeId string) string {
//captchaObj为最开始创建的图片验证码存储对象
return captchaObj.Get(codeId, false)
}
- Get()函数中第二个参数为true时,根据ID获取完验证码就要删除这个验证码
- Get()函数中第二个参数为false时,根据ID获取完验证码不会删除这个验证码
完整代码示例
1、首先定义包captcha,在其中定义配置文件config.yaml,用于指定读取哪个配置,如图:

注:此配置文件中选择的是数字验证码
2、在同级目录下定义文件config.go,用于映射配置文件的结构体,如图:

3、定义文件captchastyle.go,其中定义验证码类型以及获取验证码,如下:
package captcha
import (
"image/color"
"io/ioutil"
"log"
"github.com/mojocn/base64Captcha"
"gopkg.in/yaml.v2"
)
//图形化算术验证码
func mathConfig() *base64Captcha.DriverMath {
mathType := &base64Captcha.DriverMath{
Height: 50,
Width: 100,
NoiseCount: 0,
ShowLineOptions: base64Captcha.OptionShowHollowLine,
BgColor: &color.RGBA{
R: 40,
G: 30,
B: 89,
A: 29,
},
Fonts: nil,
}
return mathType
}
//图像化数字验证码
func digitConfig() *base64Captcha.DriverDigit {
digitType := &base64Captcha.DriverDigit{
Height: 50,
Width: 100,
Length: 5,
MaxSkew: 0.45,
DotCount: 10,
}
return digitType
}
//图形化字符串验证码
func stringConfig() *base64Captcha.DriverString {
stringType := &base64Captcha.DriverString{
Height: 100,
Width: 100,
NoiseCount: 0,
ShowLineOptions: base64Captcha.OptionShowHollowLine | base64Captcha.OptionShowSlimeLine,
Length: 4,
Source: "helloworldchinashenzhen93567210guagndong9",
BgColor: &color.RGBA{
R: 40,
G: 30,
B: 89,
A: 29,
},
Fonts: nil,
}
return stringType
}
//图形化汉字验证码
func chineseConfig() *base64Captcha.DriverChinese {
chineseType := &base64Captcha.DriverChinese{
Height: 50,
Width: 500,
NoiseCount: 0,
ShowLineOptions: base64Captcha.OptionShowSlimeLine,
Length: 2,
Source: "中国,广东,深圳市,宝安区,南山区,福田区,万里路,福永",
BgColor: &color.RGBA{
R: 40,
G: 30,
B: 89,
A: 29,
},
Fonts: nil,
}
return chineseType
}
//图形化音频验证码
func autoConfig() *base64Captcha.DriverAudio {
chineseType := &base64Captcha.DriverAudio{
Length: 4,
Language: "zh",
}
return chineseType
}
//创建验证码
func CreateCpatcha(bs base64Captcha.Store) (string, string, error) {
var driver base64Captcha.Driver
yamlfile, err := ioutil.ReadFile("captcha/config.yaml")
if err != nil {
log.Fatal(err)
}
var cn *Config
err = yaml.Unmarshal(yamlfile, &cn)
if err != nil {
log.Fatal(err)
}
switch cn.Driver {
case "math":
driver = mathConfig()
case "string":
driver = stringConfig()
case "chinese":
driver = chineseConfig()
case "digit":
driver = digitConfig()
case "audio":
driver = autoConfig()
}
// driver = mathConfig()
if driver == nil {
log.Fatal("请检查配置文件中是否没有指定验证码类型!!!")
}
c := base64Captcha.NewCaptcha(driver, bs)
id, b64s, err := c.Generate()
return id, b64s, err
}
//校验验证码,接收用户输入过来的
/*
* 验证码id是哪里来的, 是客户端调用服务端接口,服务端生成验证码的同时会生成
一个验证码id, 然后客户端输入验证码登录的时候会将输入的验证码和这个id再次
发送回服务端
* VerifyCaptcha会接收客户端传递回来的验证码id和用户输入的验证码的值,然后将
id传递给函数GetCodeAnswer()来根据id获取服务端验证码答案,然后将用户输入的
与服务器端的答案做比较如果相同返回true,否则返回false
*/
func VerifyCaptcha(id, VerifyValue string, bs base64Captcha.Store) bool {
str := getCodeAnswer(bs, id)
if str == VerifyValue {
return true
}
return false
// return result.Verify(id, VerifyValue, true)
}
//获取验证码答案
func getCodeAnswer(bs base64Captcha.Store, codeId string) string {
//bs为main()函数中创建的验证码存储对象captchaObj传递过来的
return bs.Get(codeId, false)
}
4、最后创建主配置文件,如下:
主配置文件中中定义了两个接口,GET用来获取验证码和验证码id,调用POST的时候,将用户输入的验证码和GET获取的id一起传递过去,来校验下用户输入的验证码和服务生成的验证码是否一致,一致就返回true
package main
import (
"fmt"
"log"
"project/captcha"
"time"
"github.com/gin-gonic/gin"
"github.com/mojocn/base64Captcha"
)
type verifycaptcha struct {
CaptchaID string `json:"captchaid"`
CaptchaValue string `json:"captchavalue"`
}
func main() {
var captchaObj = base64Captcha.NewMemoryStore(20000, 3*time.Minute)
router := gin.New()
//调用接口获取验证码
router.GET("/api/v1/auth/captcha", func(c *gin.Context) {
//创建图片验证码
id, b64s, err := captcha.CreateCpatcha(captchaObj)
if err != nil {
log.Fatal(err)
}
data := make(map[string]interface{})
data["verifyID"] = id
data["captcha"] = b64s
c.JSON(200, gin.H{
"code": "00000",
"msg": "OK",
"data": data,
})
})
//调用接口校验验证码
router.POST("/api/v1/auth/verifycaptcha", func(c *gin.Context) {
var v verifycaptcha
err := c.ShouldBindJSON(&v)
if err != nil {
fmt.Println(err)
return
}
res := captcha.VerifyCaptcha(v.CaptchaID, v.CaptchaValue, captchaObj)
c.JSON(400, gin.H{
"code": "10000",
"msg": res,
})
})
router.Run()
}
5、通过postman测试调用GET接口来获取验证码,如图:

- captcha:服务端生成的图片验证码,这里是以base64方式显示,图片中显示为65532
- verifyID:图片验证码
6、通过postman调用POST接口,将上述图片ID和用户输入的验证码传递过去,与服务端生成的验证码做比较,如图:

返回结果为true,说明用户输入的与服务端生成的一致
注意:base64格式的图片如何要查看需要先进行转换或者直接将其放在html的<img src=””>标签中即可


