Go整合captcha实现验证码功能

 更新时间:2023年03月01日 11:41:18   作者:BarryYan  
最近在使用Go语言搞一个用户登录&注册的功能,我们油然会产生一种增加验证码的想法。后来在GitHub上找到了这个名叫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接口时需要完整实现,也就是能真正的实现存储或缓存功能,否则验证码无法生成

到此这篇关于Go整合captcha实现验证码功能的文章就介绍到这了,更多相关Go captcha验证码内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Golang中sync.Mutex的源码分析

    Golang中sync.Mutex的源码分析

    这篇文章将带大家从源码分析一下Golang中sync.Mutex的使用,文中的示例代码讲解详细,对我们学习Golang有一定的帮助,需要的可以参考一下
    2023-03-03
  • 基于Golang实现统一加载资源的入口

    基于Golang实现统一加载资源的入口

    当我们需要在 main 函数中做一些初始化的工作,比如初始化日志,初始化配置文件,都需要统一初始化入口函数,所以本文就来编写一个统一加载资源的入口吧
    2023-05-05
  • go mock模拟接口的实现

    go mock模拟接口的实现

    本文主要介绍了go mock模拟接口的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • Go语言常见错误之将接口定义在实现方

    Go语言常见错误之将接口定义在实现方

    在Go中,接口起到一个十分关键的角色,它们提供了一种方式来定义对象的行为,而不需要知道对象的具体实现,一个常见的错误是在实现方而不是使用方定义接口,本文将详细探讨为何这样做是一个错误,以及如何避免它
    2024-01-01
  • golang中log包自定义输出日志格式与写入到文件

    golang中log包自定义输出日志格式与写入到文件

    这篇文章主要给大家介绍了关于golang中log包自定义输出日志格式与写入到文件的相关资料,日志输出在任何项目中都极其重要,是有助于后续我们排查解决程序BUG,需要的朋友可以参考下
    2023-06-06
  • Go语言实现单端口转发到多个端口

    Go语言实现单端口转发到多个端口

    这篇文章主要为大家详细介绍了Go语言实现单端口转发到多个端口,文中的示例代码讲解详细,具有一定的参考价值,对大家的学习或工作有一定的帮助,需要的小伙伴可以了解下
    2024-02-02
  • goFrame的gqueue与channe的区别

    goFrame的gqueue与channe的区别

    这篇文章主要介绍了goFrame的gqueue与channe的区别,channel的作用是用于go协程间的通信,goroutine和channel是支持高并发的重要组成部分,更多两者详细介绍需要的小伙伴可以参考下面文章内容
    2022-06-06
  • go sync.Map基本原理深入解析

    go sync.Map基本原理深入解析

    这篇文章主要为大家介绍了go sync.Map基本原理深入解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-01-01
  • 1行Go代码实现反向代理的示例

    1行Go代码实现反向代理的示例

    这篇文章主要介绍了1行Go代码实现反向代理的示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-08-08
  • Go语言面向对象中的多态你学会了吗

    Go语言面向对象中的多态你学会了吗

    面向对象中的多态(Polymorphism)是指一个对象可以具有多种不同的形态或表现方式,本文将通过一些简单的示例为大家讲解一下多态的实现,需要的可以参考下
    2023-07-07

最新评论