Go整合captcha实现验证码功能

作者:BarryYan 时间:2024-04-26 17:29:43 

最近在使用Go语言搞一个用户登录&注册的功能,说到登录&注册相关,我们油然会产生一种增加验证码的想法,因此着手实现,后来在GitHub上找到了这个名叫captcha的插件,于是就利用文档进行了初步的学习,并融入到自己的项目中,整个过程下来感觉这个插件的设计非常巧妙,所以就想写一篇文章分享一下,通过本篇文章,你会学到:

  • 利用captcha生成验证码返回到前端使用

  • 将captcha生成的验证码点击刷新

  • 将captcha生成的验证码利用Redis进行缓存

1 captcha概述

GitHub:https://github.com/dchest/captcha

captcha的使用设计流程

Go整合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

标签:Go,captcha,验证码
0
投稿

猜你喜欢

  • Python函数递归调用实现原理实例解析

    2023-01-16 12:00:52
  • 使用Javascript面向对象的思想编写ASP

    2008-06-16 12:20:00
  • 用PHP实现标准的IP Whois查询

    2023-11-14 19:35:01
  • 用SQL批量插入数据的代码

    2024-01-15 04:49:30
  • 原生js实现autocomplete插件

    2024-04-17 09:44:55
  • vuex state及mapState的基础用法详解

    2024-05-13 09:07:23
  • ORACLE 常用的SQL语法和数据对象

    2009-02-26 10:58:00
  • Python 如何批量更新已安装的库

    2023-06-05 12:15:40
  • php上传图片到指定位置路径保存到数据库的具体实现

    2024-05-09 14:48:22
  • python中随机函数random用法实例

    2023-02-09 22:13:10
  • php字符串过滤strip_tags()函数用法实例分析

    2023-09-04 14:05:00
  • Python使用 OpenCV 进行图像投影变换

    2021-09-10 03:08:19
  • Python叠加两幅栅格图像的实现方法

    2023-07-25 17:14:06
  • pycharm必知的一些简单设置方法

    2023-07-21 14:53:40
  • 深入Oracle字符集的查看与修改详解

    2023-06-25 22:13:15
  • vue封装axios与api接口管理的完整步骤

    2024-04-30 10:28:24
  • Python利用PyAutoGUI轻松搞定图片上传

    2022-11-19 23:15:18
  • 解决Pycharm界面的子窗口不见了的问题

    2022-03-06 15:21:15
  • 判断字段是否被更新 新旧数据写入Audit Log表中

    2012-01-29 17:56:33
  • Mysql数据库事务的脏读幻读及不可重复读详解

    2024-01-16 04:27:20
  • asp之家 网络编程 m.aspxhome.com