https://github.com/mojocn/base64Captcha
引入captcha,在文件中
import (
"github.com/mojocn/base64Captcha"
)
然后
go mod tidy
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
}
}
在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,
})
}
在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")
}
}
在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 }}
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()
})
}
}
默认的保存验证码的位置为mem(内存中)单机部署,如果要布置多台服务器,则可以设置保存在redis中
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
}
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)
}
}
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
}
修改上面第二步中的代码
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 商城项目-配置公共基类实现公共的成功,失败提示页面 用户登录、退出登录、以及权限判断