Go整合captcha实现验证码功能
作者:BarryYan 发布时间:2024-04-26 17:29:43
标签:Go,captcha,验证码
最近在使用Go语言搞一个用户登录&注册的功能,说到登录&注册相关,我们油然会产生一种增加验证码的想法,因此着手实现,后来在GitHub上找到了这个名叫captcha的插件,于是就利用文档进行了初步的学习,并融入到自己的项目中,整个过程下来感觉这个插件的设计非常巧妙,所以就想写一篇文章分享一下,通过本篇文章,你会学到:
利用captcha生成验证码返回到前端使用
将captcha生成的验证码点击刷新
将captcha生成的验证码利用Redis进行缓存
1 captcha概述
GitHub:https://github.com/dchest/captcha
captcha的使用设计流程
2 实现代码(使用内存缓存)
2.1 后端代码
生成验证码图片API:
//GenerateImg 生成验证码图片名称
func GenerateImg(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*") //允许访问所有域
w.Header().Add("Access-Control-Allow-Headers", "Content-Type")
d := struct {
CaptchaId string
}{
captcha.New(),
}
bytes, _ := json.Marshal(map[string]interface{}{"code": 0, "msg": "", "count": 0, "data": d.CaptchaId})
w.Write(bytes)
}
HTTP服务:
func RunHttp(port string) {
logger := log.Default()
http.Header{}.Set("Access-Control-Allow-Origin", "*")
http.HandleFunc("/user/login", controller.UserLogin) //登录API
http.HandleFunc("/img", controller.GenerateImg) //生成验证码图片API
http.Handle("/verify/", captcha.Server(captcha.StdWidth, captcha.StdHeight)) //刷新验证码API
logger.Println("Http Server Running port:", port, "...")
http.ListenAndServe(":"+port, nil)
}
启动HTTP服务:
func main() {
web.RunHttp("8000")
}
验证码验证:
//UserLogin 用户登录
func UserLogin(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Add("Access-Control-Allow-Headers", "Content-Type")
......
var m map[string]string
body, err := ioutil.ReadAll(req.Body)
if err != nil {
panic(err)
}
json.Unmarshal(body, &m)
var k = m["verify_key"]
var v = m["verify_value"]
res := captcha.VerifyString(k, v)
if res { // 验证通过
......
} else { // 验证未通过
......
}
......
}
2.2 前端代码
......
<form class="layui-form" id="form">
<h3 style="font-size: 20px;text-align: center;margin-bottom: 30px;">登录</h3>
<div class="layui-form-item">
<label class="layui-form-label">账号</label>
<div class="layui-input-inline">
<input type="text" id="loginName" placeholder="请输入账号" autocomplete="off"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">密码</label>
<div class="layui-input-inline">
<input type="password" id="loginPwd" placeholder="请输入密码" autocomplete="off"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">验证码</label>
<div class="layui-input-inline">
<input type="text" id="loginV" placeholder="请输入验证码" autocomplete="off"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" type="button" onclick="login()">立即提交</button>
<button type="button" onclick="toRegister()" class="layui-btn layui-btn-primary">注册</button>
</div>
</div>
</form>
<img id="verify" onclick="reload()"></img>
......
<input type="hidden" id="verify_key">
</body>
<script src="//unpkg.com/layui@2.6.8/dist/layui.js"></script>
<script src="//cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
<script>
const base_url = 'http://localhost:8000'
init()
function init() {
$.ajax({
url: base_url + "/img",
type: "GET",
success: function (res) {
var obj = JSON.parse(res)
$("#verify").attr("src", base_url + "/verify/" + obj.data + ".png")
$("#verify_key").attr("value", obj.data)
}
})
}
function reload() {
var url = $("#verify").attr("src");
$("#verify").attr("src", url + "?reload=" + (new Date()).getTime())
}
function login() {
var loginName = $("#loginName").val()
var loginPwd = $("#loginPwd").val()
var verify_key = $("#verify_key").val()
var loginV = $("#loginV").val()
var data = {
'login_name': loginName,
'pwd': loginPwd,
'verify_key': verify_key,
'verify_value': loginV
}
$.ajax({
url: base_url + "/user/login",
type: "POST",
data: JSON.stringify(data),
success: function (res) {
......
},
......
})
}
......
</script>
2.3 注意点
跨域问题:可加入如下代码
w.Header().Set("Access-Control-Allow-Origin", "*") //允许访问所有域
w.Header().Add("Access-Control-Allow-Headers", "Content-Type")
3 自定义Store(使用Redis缓存)
3.1 自定义对象并实现Store抽象
Redis初始化:
var (
RDB *redis.Client
TokenTimeOut = time.Second * 3600
)
func init() {
RDB = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379",
Password: "",
DB: 0,
})
}
自定义结构体&实现Store抽象:
type StoreImpl struct {
RDB *redis.Client
Expiration time.Duration
}
func (impl *StoreImpl) Set(id string, digits []byte) {
impl.RDB.Set(context.Background(), id, string(digits), impl.Expiration)
}
func (impl *StoreImpl) Get(id string, clear bool) (digits []byte) {
bytes, _ := impl.RDB.Get(context.Background(), id).Bytes()
return bytes
}
3.2 配置captcha,加入自定义Store实现
//GenerateImg 生成验证码图片名称
func GenerateImg(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*") //允许访问所有域
w.Header().Add("Access-Control-Allow-Headers", "Content-Type") //header的类型
//需要在New之前进行指定
captcha.SetCustomStore(&verify.StoreImpl{
RDB: dao.RDB,
Expiration: time.Second * 1000,
})
d := struct {
CaptchaId string
}{
captcha.New(),
}
bytes, _ := json.Marshal(map[string]interface{}{"code": 0, "msg": "", "count": 0, "data": d.CaptchaId})
w.Write(bytes)
}
3.3 注意点
需要在captcha.New()之前进行captcha.SetCustomStore()
在captcha.SetCustomStore()之后,自定义的方法实现Store接口时需要完整实现,也就是能真正的实现存储或缓存功能,否则验证码无法生成
来源:https://juejin.cn/post/7120907777429979173


猜你喜欢
- 每个程序员都绝对必须知道的关于字符集和Unicode的那点儿事(别找借口!)Unicode与字符集你曾经是否觉得HTML中的"Co
- 众所周知windows平台漏洞百出,补丁一个接一个,但总是补也补不净。我把我所知道的看asp源码的方法总结了一下,并且用c#写了个应用程序来
- 介绍海象运算符,即 := ,在 PEP 572 中被提出,并在 Python3.8 版本中发布。海象运算符的英文原名叫Assignment
- 背景:我在爬虫处理某个文本时,用到了re.findall(),而不是re.compile。远在新加坡的同事提出了质疑,认为以我的水平,不应该
- 第一步、导入需要的包import osimport scipy.io as sioimport numpy as npimport torc
- 在做项目时发现,很多场合都可能用到Input但又想让它具有select的特性,研究了一下,似乎可以实现,下面的代码可以大概说明我的意图,但实
- 这两天一直在看tensorflow中的读取数据的队列,说实话,真的是很难懂。也可能我之前没这方面的经验吧,最早我都使用的theano,什么都
- 一、什么是变量在读这篇文章前,我们需要搞懂到底是什么变量,其实一句话就能概括:变量是一个可以保存任何数据类型值的命名占位符。本篇文章将会介绍
- 本文实例为大家分享了python爬虫爬取淘宝商品的具体代码,供大家参考,具体内容如下1、需求目标 : 进去淘宝页面,搜索耐克关键词,抓取 商
- append()方法追加传递obj到现有的列表。语法以下是append()方法的语法:list.append(obj)参数&nb
- 原来图片自适应宽度一般都是通过Javascript来解决的,但是多少还是比较麻烦。还有一种通过设置外层容器overflow:hidden属性
- Firefox 的 Jetpack 可以让我们很轻松地创建 Firefox 插件,仅通过已掌握的前端技能(HTML/CSS/JS),估计让人
- 如何用数据库制作一个多用户版的计数器?代码和说明如下:count.asp' 计数器的核心程序<%Set c
- 大家都用过企业管理器中的--“收缩数据库”,里面的功能的确可以收缩数据库的日志文件(.ldf)和数据文件(.mdf),但都会发现同样的问题,
- 有时候我们可能会把CSV中的数据导入到某个数据库的表中,比如做报表分析的时候。对于这个问题,我想一点也难不倒程序人员吧!但是要是SQL Se
- 本文实例讲述了Python3实现爬取简书首页文章标题和文章链接的方法。分享给大家供大家参考,具体如下:from urllib import
- 实验环境:python版本3.9Python 3.9.7 (tags/v3.9.7:1016ef3, Aug 30 2021, 20:19:
- 客户的一台服务器出现Raid故障,经过我们的努力,数据基本恢复成功,但是其中的一个SQL Server日志文件(扩展名LDF)损坏严重,基本
- 今晚在Mac OS中搭建web服务器时遇到一点冲突,逛了几个论坛和网站,都说的太片面。先列出最正确的搭建步骤:(无论你是任何操作系统,或者任
- python读取txt文件#方式一:file = r'D:\test.txt'with open(file, 'rb