当前位置: 首页 > 工具软件 > go-captcha > 使用案例 >

[golang gin框架] 12.Gin 商城项目-base64Captcha生成图形验证码以及分布式架构中配置Captcha

常嘉平
2023-12-01

一、涉及的库

https://github.com/mojocn/base64Captcha

二、base64Captcha 的基本使用

1.引入captcha

引入captcha,在文件中
import (
    "github.com/mojocn/base64Captcha"
)

然后

go mod tidy

2.定义 captcha model

package models

//验证码属性: https://captcha.mojotv.cn/
import (
    "github.com/mojocn/base64Captcha"
    "image/color"
)

创建store,保存验证码的位置,默认为mem(内存中)单机部署,如果要布置多台服务器,则可以设置保存在redis中
var store = base64Captcha.DefaultMemStore

//配置RedisStore, RedisStore实现base64Captcha.Store接口
//var store base64Captcha.Store = RedisStore{}

//获取验证码
func MakeCaptcha() (string, string, error) {
    //定义一个driver
    var driver base64Captcha.Driver
    //创建一个字符串类型的验证码驱动DriverString, DriverChinese :中文驱动
    driverString := base64Captcha.DriverString{
        Height:          40,                                     //高度
        Width:           100,                                    //宽度
        NoiseCount:      0,                                      //干扰数
        ShowLineOptions: 2 | 4,                                  //展示个数
        Length:          1,                                      //长度
        Source:          "1234567890qwertyuioplkjhgfdsazxcvbnm", //验证码随机字符串来源
        BgColor: &color.RGBA{ // 背景颜色
            R: 3,
            G: 102,
            B: 214,
            A: 125,
        },
        Fonts: []string{"wqy-microhei.ttc"}, // 字体
    }
    driver = driverString.ConvertFonts()
    //生成验证码
    c := base64Captcha.NewCaptcha(driver, store)
    id, b64s, err := c.Generate()
    return id, b64s, err
}

//校验验证码
func VerifyCaptcha(id string, VerifyValue string) bool {
    // 参数说明: id 验证码id, verifyValue 验证码的值, true: 验证成功后是否删除原来的验证码
    if store.Verify(id, VerifyValue, true) {
        return true
    } else {
        return false
    }
}

3.定义控制器获取验证码

在LoginController控制器中定义获取验证码的方法
//获取验证码,验证验证码
func (con LoginController) Captcha(c *gin.Context) {
    id, b64s, err := models.MakeCaptcha()
    if err != nil {
        fmt.Println(err)
    }
    c.JSON(http.StatusOK, gin.H{
        "captchaId":    id,
        "captchaImage": b64s,
    })
}

4.定义控制器验证验证码

在LoginController控制器中定义 验证验证码的方法
//执行登录操作
func (con LoginController) DoIndex(c *gin.Context) {
    //获取表单中的数据
    captchaId := c.PostForm("captchaId")     // 验证码id
    verifyValue := c.PostForm("verifyValue") //验证码的值
    //获取用户名以及密码
    username := c.PostForm("username")
    password := c.PostForm("password")

    // 1.判断验证码是否验证成功
    if flag := models.VerifyCaptcha(captchaId, verifyValue); flag {
        //2.查询数据库,判断用户以及密码是否正确
        userinfo := []models.Manager{}
        password = models.Md5(password)
        models.DB.Where("username = ? and password = ? ", username, password).Find(&userinfo)
        if len(userinfo) > 0 {
            //3.执行登录,保存用户信息,执行跳转操作
            session := sessions.Default(c)
            //注意: session.Set没法保存结构体对应的切片,所以需要把结构体转换成json字符串
            userinfoSlice, _ := json.Marshal(userinfo)
            session.Set("userinfo", string(userinfoSlice))
            session.Save()
            con.Success(c, "登录成功", "/admin")
        } else {
            con.Error(c, "用户名或密码错误", "/admin/login")
        }
    } else {
        con.Error(c, "验证码验证失败", "/admin/login")
    }
}

5.静态页面显示验证码

在templates/login/index.tml下,生成带验证码的登录表单
    {{ define "admin/login/login.html" }}
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
            "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
      <title>用户登录</title>
        <link rel="stylesheet" href="/static/admin/css/login.css">
        <script type="text/javascript" src="/static/admin/bootstrap/js/jquery-1.10.1.js"></script>
        <script type="text/javascript" src="/static/admin/js/login.js"></script>
    </head>
    <body>
    <div class="container">
            <div id="login">
                    <form action="/admin/doLogin" method="post" id="myform">
                        <input type="hidden" name="captchaId" id="captchaId">
                        <div class="l_title">商城后台管理系统</div>
                        <dl>
                            <dd>管理员姓名:<input class="text" type="text" name="username" id="username"></dd>
                            <dd>管理员密码:<input class="text" type="password" name="password" id="password"></dd>
                            <dd>验 证 码:<input id="verifyValue" type="text" name="verifyValue">
                                <img id="captchaImg" >
                             </dd>
                            <dd><input type="submit" class="submit" name="dosubmit" value=""></dd>
                        </dl>
                    </form>
                </div>
    </div>
    </body>
    </html>
    {{ end }}

6.Login.js 验证验证码

Login.js 获取验证码,验证码改变js方法
$(function () {
    loginApp.init();
})

var loginApp = {
    init: function () {
        this.getCaptcha()  // 调用获取验证码方法
        this.captchaImgChange()  // 调用验证码改变方法
    },
    getCaptcha: function () { // 获取验证码
        $.get("/admin/captcha?t=" + Math.random(), function (response) { // ? t= 随机数,防止浏览器缓存
            //把验证码赋值给input
            $("#captchaId").val(response.captchaId)
            $("#captchaImg").attr("src", response.captchaImage)
        })
    },
    captchaImgChange: function () { // 验证码改变
        var that = this;
        $("#captchaImg").click(function () {
            that.getCaptcha()
        })
    }
}

7.base64Captcha 的数据存储到 Redis 中

默认的保存验证码的位置为mem(内存中)单机部署,如果要布置多台服务器,则可以设置保存在redis中

7.1自定义 store 需要实现 Store 这个接口

package base64Captcha

// Store An object implementing Store interface can be registered with SetCustomStore
// function to handle storage and retrieval of captcha ids and solutions for
// them, replacing the default memory store.
//
// It is the responsibility of an object to delete expired and used captchas
// when necessary (for example, the default memory store collects them in Set
// method after the certain amount of captchas has been stored.)
type Store interface {
    // Set sets the digits for the captcha id.
    Set(id string, value string) error

    // Get returns stored digits for the captcha id. Clear indicates
    // whether the captcha must be deleted from the store.
    Get(id string, clear bool) string

    //Verify captcha's answer directly
    Verify(id, answer string, clear bool) bool
}

7.2 新建 redisCore.go

package models

//redis官网: github.com/go-redis
//下载go-redis: go get github.com/redis/go-redis/v9
//连接redis数据库核心代码

import (
    "context"
    "github.com/redis/go-redis/v9"
)

//全局使用,就需要把定义成公有的
var ctxRedis = context.Background()

var (
    RedisDb *redis.Client
)

//自动初始化数据库
func init() {
    RedisDb = redis.NewClient(&redis.Options{
        Addr:     "127.0.0.1:6379",
        Password: "", // no password set
        DB:       0,  // use default DB
    })

    //连接redis
    _, err := RedisDb.Ping(ctxRedis).Result()
    //判断连接是否成功
    if err != nil {
        println(err)
    }
}

7.3 新建 redisStore.go

package models

/**
使用redis需实现Store中的三个方法
type Store interface {
    // Set sets the digits for the captcha id.
    Set(id string, value string)

    // Get returns stored digits for the captcha id. Clear indicates
    // whether the captcha must be deleted from the store.
    Get(id string, clear bool) string

    //Verify captcha's answer directly
    Verify(id, answer string, clear bool) bool
}
 */

import (
    "context"
    "fmt"
    "time"
)

var ctx = context.Background()

const CAPTCHA = "captcha:"

type RedisStore struct {
}

//实现设置 captcha 的方法
func (r RedisStore) Set(id string, value string) error {
    key := CAPTCHA + id
    err := RedisDb.Set(ctx, key, value, time.Minute*2).Err()
    return err
}

//实现获取 captcha 的方法
func (r RedisStore) Get(id string, clear bool) string {
    key := CAPTCHA + id
    //获取 captcha
    val, err := RedisDb.Get(ctx, key).Result()
    if err != nil {
        fmt.Println(err)
        return ""
    }
    //如果clear == true, 则删除
    if clear {
        err := RedisDb.Del(ctx, key).Err()
        if err != nil {
            fmt.Println(err)
            return ""
        }
    }
    return val
}

//实现验证 captcha 的方法
func (r RedisStore) Verify(id, answer string, clear bool) bool {
    v := RedisStore{}.Get(id, clear)
    return v == answer
}

7.4 配置 store 实现 base64Captcha.Store 这个接口

修改上面第二步中的代码
package models

//验证码属性: https://captcha.mojotv.cn/
import (
    "github.com/mojocn/base64Captcha"
    "image/color"
)

//创建store,保存验证码的位置,默认为mem(内存中)单机部署,如果要布置多台服务器,则可以设置保存在redis中
//var store = base64Captcha.DefaultMemStore

//配置RedisStore, RedisStore实现base64Captcha.Store接口
var store base64Captcha.Store = RedisStore{}

//获取验证码
func MakeCaptcha() (string, string, error) {
    //定义一个driver
    var driver base64Captcha.Driver
    //创建一个字符串类型的验证码驱动DriverString, DriverChinese :中文驱动
    driverString := base64Captcha.DriverString{
        Height:          40,                                     //高度
        Width:           100,                                    //宽度
        NoiseCount:      0,                                      //干扰数
        ShowLineOptions: 2 | 4,                                  //展示个数
        Length:          1,                                      //长度
        Source:          "1234567890qwertyuioplkjhgfdsazxcvbnm", //验证码随机字符串来源
        BgColor: &color.RGBA{ // 背景颜色
            R: 3,
            G: 102,
            B: 214,
            A: 125,
        },
        Fonts: []string{"wqy-microhei.ttc"}, // 字体
    }
    driver = driverString.ConvertFonts()
    //生成验证码
    c := base64Captcha.NewCaptcha(driver, store)
    id, b64s, err := c.Generate()
    return id, b64s, err
}

//校验验证码
func VerifyCaptcha(id string, VerifyValue string) bool {
    // 参数说明: id 验证码id, verifyValue 验证码的值, true: 验证成功后是否删除原来的验证码
    if store.Verify(id, VerifyValue, true) {
        return true
    } else {
        return false
    }
}

ok,base64Captcha生成图形验证码以及分布式架构中配置Captcha操作就完成了

[上一节][golang gin框架] 11.Gin 商城项目后台管理系统-控制器配置,views模板分离,局部刷新架构

[下一节][golang gin框架] 13.Gin 商城项目-配置公共基类实现公共的成功,失败提示页面 用户登录、退出登录、以及权限判断

 类似资料: