j
jaryue
V1
2023/05/25阅读:13主题:默认主题
使用captcha库实现人机验证的图片验证
安装captcha库
使用go get命令获取captcha库
go get github.com/dchest/captcha
构建响应函数
// 发送图片验证码图片(gee7为自搭建web框架,可使用gin框架代替)
func Picverfi(db *sql.DB) gee7.HandlerFunc {
return func(ctx *gee7.Context) {
// 生成验证码
id := uuid.New().String() //生成唯一标识符
code := captcha.RandomDigits(4)
img := captcha.NewImage(id, code, captcha.StdWidth, captcha.StdHeight)
var buf bytes.Buffer
_, err := img.WriteTo(&buf)
if err != nil {
ctx.Returnfunc(401, "出错了,点击重试", nil)
}
// 转化为base64
encodedImage := base64.StdEncoding.EncodeToString(buf.Bytes())
// 将验证码和图片id存储到数据库中
verificationCode := VerificationCode{PicCode: code, CreatedAt: time.Now().Unix()}
_, err = db.Exec("INSERT INTO verification_codes (id, code, created_at) VALUES (?, ?, ?)", id, verificationCode.PicCode, verificationCode.CreatedAt)
if err != nil {
ctx.Returnfunc(http.StatusInternalServerError, "Internal Server Error:"+err.Error(), nil)
return
}
// 返回图片与唯一标识符
ctx.Returnfunc(200, "ok", gee7.H{
"picid": id,
"png": encodedImage,
})
fmt.Printf("id=%#v\ncode=%d", id, code)
}
}
gee7为自搭建web框架,可使用gin框架代替
需要了解gee7框架的内容可以访问:
下面对逻辑进行解析
-
最核心的的内容是图片验证码的生成与响应
// 生成验证码图片
img := captcha.NewImage(id, code, captcha.StdWidth, captcha.StdHeight)//其中id为标识符,code为验证码
//读取验证码图片
var buf bytes.Buffer
_, err := img.WriteTo(&buf)
if err != nil {
ctx.Returnfunc(401, "出错了,点击重试", nil)
}
// 将验证码图片转化为base64格式
encodedImage := base64.StdEncoding.EncodeToString(buf.Bytes())
这时输出encodedImage给前端,前端进行解码就可以看到验证码图片了,
验证码图片的问题解决了,接下来就是验证的逻辑
-
验证逻辑
将验证码存入数据库,当用户验证的时候在数据库中查找是否有这一条验证码
但是还需要确定用户上传的验证码是服务器发送的图片中的验证码,所以就需要对验证码进行标识,在用户提交验证的时候通过表示查找验证码,这样就确保验证码的唯一对应性
我们这里使用uuid库生成唯一标识符,这种标识符不重复,避免数据冲突的错误
id := uuid.New().String() //生成唯一标识符
再加上一个验证码过期时间的条件,就完成了基本的验证逻辑
如果需要减少空间浪费,可以在通过验证之后顺手增加一条删除验证码信息的代码,在通过验证之后删除MySQL中对应的数据,减少空间浪费.
验证逻辑:
// 图片验证码验证操作:用户传入图片id(唯一标识符发送图片信息时给的),+验证码
func Verifypiccode(db *sql.DB, id string, code []byte) error {
var createdAt int64
err := db.QueryRow("SELECT created_at FROM verification_codes WHERE id = ? AND code = ?", id, code).Scan(&createdAt)
if err != nil {
return err
}
// 删除验证码
db.Exec("DELETE FROM verification_codes WHERE id = ?", id)
if time.Now().Unix() > createdAt+5*60 { //时效5分钟
return fmt.Errorf("验证码过期")
}
return nil
}
前端vue3组件
<template>
<div>
<button @click="getVerificationImage">获取验证码图片</button>
<div v-if="verificationImage">
<img :src="decodeBase64(verificationImage.png)" alt="验证码图片">
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
verificationImage: null,
picid: ''
};
},
methods: {
async getVerificationImage() {
try {
const response = await axios.get('http://localhost:8888/verifypic');
if (response.data.code === 200) {
this.verificationImage = response.data.data;
this.picid = response.data.data.picid;
// 触发自定义事件,将 picid 传递给父组件
this.$emit('verificationImage', this.picid);
} else {
console.error(response.data.msg);
}
} catch (error) {
console.error('获取验证码图片失败', error);
}
},
decodeBase64(base64Data) {
return `data:image/png;base64, ${base64Data}`;
}
}
};
</script>
作者介绍
j
jaryue
V1