该三方库支持5种验证方法:
支持:
- 数字验证码
- 公式
- 字母
- 汉字
- 音频
下面的代码中只有数字、字母、数字+字母的形式
在代码的注释中,我已经写出了用法、理解等,代码如下:
Go
package main
import (
// 标准库,提供图像颜色处理
//"image/color"
"net/http"
"time"
// 三方库解决跨域问题
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
// 三方库实现图片验证码 别名base64Captcha 可支持字母、数字的验证数据
base64Captcha "github.com/mojocn/base64Captcha"
)
// Math 配置参数
// var (
// Height = 70
// Width = 240
// NoiseCount = 0
// ShowLineOptions = base64Captcha.OptionShowHollowLine
// BgColor = &color.RGBA{
// R: 144,
// G: 238,
// B: 144,
// A: 10,
// }
// FontsStorage base64Captcha.FontsStorage
// Fonts []string
// )
// 全局变量 用于模拟存储用户信息的Mysql数据库
var users = make(map[string]string)
var store = base64Captcha.DefaultMemStore
// 音频的验证码自行探索
//var driver = base64Captcha.DefaultDriverDigit // 数字
//自定义验证码:
//var driver = base64Captcha.NewDriverMath(Height, Width, NoiseCount, ShowLineOptions, BgColor, FontsStorage, Fonts) // 字母
var driver = base64Captcha.NewDriverString(
80, 240, 6, 1, 4,
"123456789abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ", // 包含数字和字母的字符集
nil, nil, nil,
) // 字符串:数字+字母
// 生成验证码并返回图片
func generateCaptcha(c *gin.Context) {
captcha := base64Captcha.NewCaptcha(driver, store)
// 生成验证码(返回的 id:验证码id,base64编码的验证码图片,验证码答案,错误信息)
id, b64, _, err := captcha.Generate()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "验证码生成失败"})
return
}
c.JSON(http.StatusOK, gin.H{
"captcha_id": id,
"captcha_img": b64,
})
}
// 注册接口
func register(c *gin.Context) {
var json struct {
Username string `json:"username"`
Password string `json:"password"`
CaptchaId string `json:"captcha_id"`
CaptchaAns string `json:"captcha_ans"`
}
if err := c.ShouldBindJSON(&json); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "请求数据格式错误"})
return
}
// 验证验证码
if !store.Verify(json.CaptchaId, json.CaptchaAns, true) {
c.JSON(http.StatusBadRequest, gin.H{"error": "验证码错误"})
return
}
// 注册用户(简单模拟)
if _, exists := users[json.Username]; exists {
c.JSON(http.StatusBadRequest, gin.H{"error": "用户已存在"})
return
}
// 存储用户数据
users[json.Username] = json.Password
c.JSON(http.StatusOK, gin.H{"message": "注册成功"})
}
// 登录接口
func login(c *gin.Context) {
var json struct {
Username string `json:"username"`
Password string `json:"password"`
CaptchaId string `json:"captcha_id"`
CaptchaAns string `json:"captcha_ans"`
}
if err := c.ShouldBindJSON(&json); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "请求数据格式错误"})
return
}
// 验证验证码(参数:id、answer不用说了;clear:使用后是否清除验证码 )
if !store.Verify(json.CaptchaId, json.CaptchaAns, true) {
c.JSON(http.StatusBadRequest, gin.H{"error": "验证码错误"})
return
}
// 验证用户名和密码
storedPassword, exists := users[json.Username]
if !exists || storedPassword != json.Password {
c.JSON(http.StatusUnauthorized, gin.H{"error": "用户名或密码错误"})
return
}
c.JSON(http.StatusOK, gin.H{"message": "登录成功"})
}
func main() {
r := gin.Default()
// 配置 CORS 中间件
r.Use(cors.New(cors.Config{
AllowOrigins: []string{"http://127.0.0.1:5500"}, // 前端的 URL
AllowMethods: []string{"GET", "POST"},
AllowHeaders: []string{"Origin", "Content-Type"},
ExposeHeaders: []string{"Content-Length"},
AllowCredentials: true,
MaxAge: 12 * time.Hour,
}))
// 注册路由
r.GET("/captcha", generateCaptcha)
r.POST("/register", register)
r.POST("/login", login)
// 启动服务器
r.Run("127.0.0.1:8080")
}
追问:在验证码进行验证的时候,我只是获取了用户的输入,就直接调用Verify方法进行验证了。那么之前生成的验证码的答案在哪里?
答案:其实该库自己维护一个全局变量,当使用库时,就已经进行了初始化。MemoryStore用来短暂的存储当前生成的验证码。
我们可能最初会想到使用redis数据库进行缓存,但是一般的使用场景中,我们其实只需要一个短暂的答案就可以了,所以并不需要,当然也可以。
想了解的,可以参考:一文搞懂Go整合captcha实现验证码功能-腾讯云开发者社区-腾讯云https://cloud.tencent.com/developer/article/2388090
前端验证代码:(比较简陋,我直接把登录和注册放到一起,可以直接尝试)
index.html
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>登录和注册</title>
<style>
body {
font-family: Arial, sans-serif;
padding: 20px;
}
input {
margin: 10px 0;
padding: 8px;
}
#captchaImg {
margin-top: 10px;
cursor: pointer;
}
</style>
</head>
<body>
<h2>注册</h2>
<label for="registerUsername">用户名</label>
<input type="text" id="registerUsername" required>
<br>
<label for="registerPassword">密码</label>
<input type="password" id="registerPassword" required>
<br>
<label for="registerCaptchaAns">验证码</label>
<input type="text" id="registerCaptchaAns" required>
<br>
<img id="registerCaptchaImg" src="" alt="验证码" onclick="getCaptcha('register')" title="点击刷新验证码">
<input type="hidden" id="registerCaptchaId">
<br>
<button onclick="register()">注册</button>
<h2>登录</h2>
<label for="loginUsername">用户名</label>
<input type="text" id="loginUsername" required>
<br>
<label for="loginPassword">密码</label>
<input type="password" id="loginPassword" required>
<br>
<label for="loginCaptchaAns">验证码</label>
<input type="text" id="loginCaptchaAns" required>
<br>
<img id="loginCaptchaImg" src="" alt="验证码" onclick="getCaptcha('login')" title="点击刷新验证码">
<input type="hidden" id="loginCaptchaId">
<br>
<button onclick="login()">登录</button>
<script src="scripts.js"></script>
</body>
</html>
scripts.js
javascript
// 获取验证码函数
function getCaptcha(context) {
fetch('http://localhost:8080/captcha')
.then(response => response.json())
.then(data => {
if (context === 'register') {
document.getElementById('registerCaptchaImg').src = data.captcha_img;
document.getElementById('registerCaptchaId').value = data.captcha_id;
} else if (context === 'login') {
document.getElementById('loginCaptchaImg').src = data.captcha_img;
document.getElementById('loginCaptchaId').value = data.captcha_id;
}
})
.catch(error => {
console.error('Error fetching captcha:', error);
});
}
// 注册函数
function register() {
const username = document.getElementById('registerUsername').value;
const password = document.getElementById('registerPassword').value;
const captchaId = document.getElementById('registerCaptchaId').value;
const captchaAns = document.getElementById('registerCaptchaAns').value;
const data = {
username,
password,
captcha_id: captchaId,
captcha_ans: captchaAns,
};
fetch('http://localhost:8080/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
.then(response => response.json())
.then(data => {
if (data.error) {
alert('注册失败: ' + data.error);
getCaptcha('register'); // 刷新验证码
} else {
alert('注册成功');
getCaptcha('register'); // 刷新验证码
}
})
.catch(error => {
console.error('Error during registration:', error);
});
}
// 登录函数
function login() {
const username = document.getElementById('loginUsername').value;
const password = document.getElementById('loginPassword').value;
const captchaId = document.getElementById('loginCaptchaId').value;
const captchaAns = document.getElementById('loginCaptchaAns').value;
const data = {
username,
password,
captcha_id: captchaId,
captcha_ans: captchaAns,
};
fetch('http://localhost:8080/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
.then(response => response.json())
.then(data => {
if (data.error) {
alert('登录失败: ' + data.error);
getCaptcha('login'); // 刷新验证码
} else {
alert('登录成功');
getCaptcha('login'); // 刷新验证码
}
})
.catch(error => {
console.error('Error during login:', error);
});
}
// 页面加载时自动获取注册和登录验证码
window.onload = function () {
getCaptcha('register');
getCaptcha('login');
};