29 KiB
English | 中文
Go Captcha 是功能强大、模块化且高度可定制的行为式验证码库,支持多种交互式验证码类型:点选(Click)、滑动(Slide)、拖拽(Drag-Drop) 和 旋转(Rotate)。
⭐️ 如果能帮助到你,请随手给点一个star
QQ交流群:178498936
项目生态
名称 | 描述 |
---|---|
document | GoCaptcha 文档 |
online demo | GoCaptcha 在线演示 |
go-captcha-example | Golang + 前端 + APP实例 |
go-captcha-assets | Golang 内嵌素材资源 |
go-captcha | Golang 验证码 |
go-captcha-jslib | Javascript 验证码 |
go-captcha-vue | Vue 验证码 |
go-captcha-react | React 验证码 |
go-captcha-angular | Angular 验证码 |
go-captcha-svelte | Svelte 验证码 |
go-captcha-solid | Solid 验证码 |
go-captcha-uni | UniApp 验证码,兼容 App、小程序、快应用等 |
go-captcha-service | GoCaptcha 服务,支持二进制、Docker镜像等方式部署, 提供 HTTP/GRPC 方式访问接口, 可用单机模式和分布式(服务发现、负载均衡、动态配置等) |
go-captcha-service-sdk | GoCaptcha 服务SDK工具包,包含 HTTP/GRPC 请求服务接口, 支持静态模式、服务发现、负载均衡 |
... |
核心特性
- 多样化验证码类型:支持点选、滑动、旋转和拖拽四种行为式验证码,适应不同交互场景。
- 高度可定制化:通过选项(
Options
)和资源(Resources
)支持图像、字体、颜色、角度、大小等灵活配置。 - 高级图像处理:内置动态图像生成和处理功能,支持主图像、缩略图、拼图块和阴影效果的生成。
- 模块化架构:代码结构清晰,遵循 Go 语言最佳实践,易于扩展和维护。
- 高性能设计:优化资源管理和图像生成,适合高并发场景。
- 跨平台兼容:生成的验证码图像可无缝集成到 Web 应用、移动应用或其他需要验证码的系统。
验证码类型
go-captcha
支持以下四种验证码类型,每种类型具有独特的交互方式、生成逻辑和应用场景:
- 点选验证码(Click):用户在主图像中点击指定的点或字符,支持文本模式和图形模式。
- 滑动验证码(Slide):用户将拼图块滑动到主图像中的正确位置,支持基本模式和拖拽模式。
- 拖拽验证码(DragDrop):滑动验证码的变体,允许用户在更大范围内拖动拼图块到目标位置。
- 旋转验证码(Rotate):用户旋转缩略图使其与主图像的角度对齐。
设置Go代理
- Window
$ set GO111MODULE=on
$ set GOPROXY=https://goproxy.io,direct
### The Golang 1.13+ can be executed directly
$ go env -w GO111MODULE=on
$ go env -w GOPROXY=https://goproxy.io,direct
- Linux or Mac
$ export GO111MODULE=on
$ export GOPROXY=https://goproxy.io,direct
### or
$ echo "export GO111MODULE=on" >> ~/.profile
$ echo "export GOPROXY=https://goproxy.cn,direct" >> ~/.profile
$ source ~/.profile
安装
$ go get -u github.com/wenlng/go-captcha/v2@latest
按需引入模块
package main
// 按需求引入对应的模块
import "github.com/wenlng/go-captcha/v2/${click|slide|rotate}"
func main(){
// ....
}
🖖 点选验证码(Click)
点选验证码要求用户在主图像中点击指定的点或字符,适合需要快速验证的场景。支持两种模式:
- 文本模式:显示字符(如字母、数字或中文),用户点击对应字符。
- 图形模式:显示图形(如图标或形状),用户点击对应图形。
工作原理
- 生成主图像(
masterImage
):包含随机分布的点或字符,通常为 JPEG 格式。 - 生成缩略图(
thumbImage
):显示需要点击的目标点或字符,通常为 PNG 格式。 - 用户交互:用户点击主图像中的坐标,前端捕获坐标并发送到后端。
- 验证逻辑:后端比较用户点击的坐标与目标点(
dots
)的坐标是否匹配。
代码示例
package main
import (
"encoding/json"
"fmt"
"image"
"log"
"io/ioutil"
"github.com/golang/freetype"
"github.com/golang/freetype/truetype"
"github.com/wenlng/go-captcha/v2/base/option"
"github.com/wenlng/go-captcha/v2/click"
"github.com/wenlng/go-captcha/v2/base/codec"
)
var textCapt click.Captcha
func init() {
builder := click.NewBuilder(
click.WithRangeLen(option.RangeVal{Min: 4, Max: 6}),
click.WithRangeVerifyLen(option.RangeVal{Min: 2, Max: 4}),
// ...
)
// 可以使用预置的素材资源:https://github.com/wenlng/go-captcha-assets
fontN, err := loadFont("../resources/fzshengsksjw_cu.ttf")
if err != nil {
log.Fatalln(err)
}
bgImage, err := loadPng("../resources/bg.png")
if err != nil {
log.Fatalln(err)
}
builder.SetResources(
click.WithChars([]string{"这", "是", "随", "机", "的", "文", "本", "种", "子", "呀"}),
click.WithFonts([]*truetype.Font{
fontN,
}),
click.WithBackgrounds([]image.Image{
bgImage,
}),
)
textCapt = builder.Make()
}
func loadPng(p string) (image.Image, error) {
imgBytes, err := ioutil.ReadFile(p)
if err != nil {
return nil, err
}
return codec.DecodeByteToPng(imgBytes)
}
func loadFont(p string) (*truetype.Font, error) {
fontBytes, err := ioutil.ReadFile(p)
if err != nil {
panic(err)
}
return freetype.ParseFont(fontBytes)
}
func main() {
captData, err := textCapt.Generate()
if err != nil {
log.Fatalln(err)
}
dotData := captData.GetData()
if dotData == nil {
log.Fatalln(">>>>> generate err")
}
dots, _ := json.Marshal(dotData)
fmt.Println(">>>>> ", string(dots))
var mBase64, tBase64 string
mBase64, err = captData.GetMasterImage().ToBase64()
if err != nil {
fmt.Println(err)
}
tBase64, err = captData.GetThumbImage().ToBase64()
if err != nil {
fmt.Println(err)
}
fmt.Println(">>>>> ", mBase64)
fmt.Println(">>>>> ", tBase64)
//err = captData.GetMasterImage().SaveToFile("../resources/master.jpg", option.QualityNone)
//if err != nil {
// fmt.Println(err)
//}
//err = captData.GetThumbImage().SaveToFile("../resources/thumb.png")
//if err != nil {
// fmt.Println(err)
//}
}
创建实例
- builder.Make() 中文文本、字母数字混合点选
- builder.MakeShape() 图形点选
配置选项
click.NewBuilder(click.WithXxx(), ...) 或 builder.SetOptions(click.WithXxx(), ...)
Options | Desc |
---|---|
主图 | |
click.WithImageSize(option.Size) | 设置主图尺寸,默认 300x220 |
click.WithRangeLen(option.RangeVal) | 设置随机内容长度范围 |
click.WithRangeAnglePos([]option.RangeVal) | 设置随机角度范围 |
click.WithRangeSize(option.RangeVal) | 设置随机内容大小范围 |
click.WithRangeColors([]string) | 设置随机颜色 |
click.WithDisplayShadow(bool) | 设置是否显示阴影 |
click.WithShadowColor(string) | 设置阴影颜色 |
click.WithShadowPoint(option.Point) | 设置阴影偏移位置 |
click.WithImageAlpha(float32) | 设置主图透明度 |
click.WithUseShapeOriginalColor(bool) | 设置是否使用图形原始颜色,"图形点选"有效 |
缩略图 | |
click.WithThumbImageSize(option.Size) | 设置缩略尺寸,默认 150x40 |
click.WithRangeVerifyLen(option.RangeVal) | 设置校验内容的随机长度范围 |
click.WithDisabledRangeVerifyLen(bool) | 禁用校验内容的随机长度,与主图内容的长度保持一致 |
click.WithRangeThumbSize(option.RangeVal) | 设置随机缩略内容随机大小范围 |
click.WithRangeThumbColors([]string) | 设置缩略随机颜色范围 |
click.WithRangeThumbBgColors([]string) | 设置缩略随机背景颜色范围 |
click.WithIsThumbNonDeformAbility(bool) | 设置缩略图内容不变形,不受背景影响 |
click.WithThumbBgDistort(int) | 设置缩略图背景扭曲 option.DistortLevel1 至 option.DistortLevel5 |
click.WithThumbBgCirclesNum(int) | 设置缩略图绘制小圆点数量 |
click.WithThumbBgSlimLineNum(int) | 设置缩略图绘制线条数量 |
设置资源
builder.SetResources(click.WithXxx(), ...)
Options | Desc |
---|---|
click.WithChars([]string) | 设置文本种子 |
click.WithShapes(map[string]image.Image) | 设置图形种子 |
click.WithFonts([]*truetype.Font) | 设置字体 |
click.WithBackgrounds([]image.Image) | 设置主图背景 |
click.WithThumbBackgrounds([]image.Image) | 设置缩略图背景 |
验证码数据
captData, err := capt.Generate()
Method | Desc |
---|---|
GetData() map[int]*Dot | 获取当前校验的信息 |
GetMasterImage() imagedata.JPEGImageData | 获取主图 |
GetThumbImage() imagedata.PNGImageData | 获取缩略图 |
验证码校验
ok := click.Validate(srcX, srcY, X, Y, width, height, paddingValue)
Params | Desc |
---|---|
srcX | 用户交互的 X 值 |
srcY | 用户交互的 Y 值 |
X | 验证码校验的 X 值 |
Y | 验证码校验的 Y 值 |
width | 验证码校验的 Width 值 |
height | 验证码校验的 Height 值 |
paddingValue | 控制误差值 |
注意事项
- 字符集(
chars
)或图形集(shapes
)的长度必须大于rangeLen.Max
,否则会触发CharRangeLenErr
或ShapesRangeLenErr
。 - 图形模式需要提供有效的图像资源(
shapeMaps
),否则会触发ShapesTypeErr
。 - 背景图像不能为空,否则会触发
EmptyBackgroundImageErr
。
🖖 滑动/拖拽验证码(Slide/Drag-Drop)
滑动验证码要求用户将拼图块滑动到主图像中的正确位置,支持两种模式:
- 基本模式:拼图块沿固定 Y 轴滑动,适合简单验证场景。
- 拖拽模式:拼图块可以在更大范围内自由拖动,适合需要更高交互自由度的场景。
工作原理
- 生成主图像(
masterImage
):包含拼图块的缺口和阴影效果,通常为 JPEG 格式。 - 生成拼图图像(
tileImage
):用户需要滑动的拼图块,通常为 PNG 格式。 - 用户交互:用户滑动拼图块到目标位置(
TileX
,TileY
),前端捕获滑动终点坐标。 - 验证逻辑:后端比较用户滑动的位置与目标位置是否匹配。
代码示例
package main
import (
"encoding/json"
"fmt"
"image"
"log"
"io/ioutil"
"github.com/wenlng/go-captcha/v2/base/option"
"github.com/wenlng/go-captcha/v2/slide"
"github.com/wenlng/go-captcha/v2/base/codec"
)
var slideTileCapt slide.Captcha
func init() {
builder := slide.NewBuilder()
// 可以使用预置的素材资源:https://github.com/wenlng/go-captcha-assets
bgImage, err := loadPng("../resources/bg.png")
if err != nil {
log.Fatalln(err)
}
bgImage1, err := loadPng("../resources/bg1.png")
if err != nil {
log.Fatalln(err)
}
graphs := getSlideTileGraphArr()
builder.SetResources(
slide.WithGraphImages(graphs),
slide.WithBackgrounds([]image.Image{
bgImage,
bgImage1,
}),
)
slideTileCapt = builder.Make()
}
func getSlideTileGraphArr() []*slide.GraphImage {
tileImage1, err := loadPng("../resources/tile-1.png")
if err != nil {
log.Fatalln(err)
}
tileShadowImage1, err := loadPng("../resources/tile-shadow-1.png")
if err != nil {
log.Fatalln(err)
}
tileMaskImage1, err := loadPng("../resources/tile-mask-1.png")
if err != nil {
log.Fatalln(err)
}
return []*slide.GraphImage{
{
OverlayImage: tileImage1,
ShadowImage: tileShadowImage1,
MaskImage: tileMaskImage1,
},
}
}
func main() {
captData, err := slideTileCapt.Generate()
if err != nil {
log.Fatalln(err)
}
blockData := captData.GetData()
if blockData == nil {
log.Fatalln(">>>>> generate err")
}
block, _ := json.Marshal(blockData)
fmt.Println(">>>>>", string(block))
var mBase64, tBase64 string
mBase64, err = captData.GetMasterImage().ToBase64()
if err != nil {
fmt.Println(err)
}
tBase64, err = captData.GetTileImage().ToBase64()
if err != nil {
fmt.Println(err)
}
fmt.Println(">>>>> ", mBase64)
fmt.Println(">>>>> ", tBase64)
//err = captData.GetMasterImage().SaveToFile("../resources/master.jpg", option.QualityNone)
//if err != nil {
// fmt.Println(err)
//}
//err = captData.GetTileImage().SaveToFile("../resources/thumb.png")
//if err != nil {
// fmt.Println(err)
//}
}
func loadPng(p string) (image.Image, error) {
imgBytes, err := ioutil.ReadFile(p)
if err != nil {
return nil, err
}
return codec.DecodeByteToPng(imgBytes)
}
创建实例
- builder.Make() 滑动式
- builder.MakeDragDrop() 区域内拖拽式
配置选项
slide.NewBuilder(slide.WithXxx(), ...) 或 builder.SetOptions(slide.WithXxx(), ...)
Options | Desc |
---|---|
slide.WithImageSize(*option.Size) | 设置主图尺寸,默认 300x220 |
slide.WithImageAlpha(float32) | 设置主图透明度 |
slide.WithRangeGraphSize(val option.RangeVal) | 设置图形随机尺寸范围 |
slide.WithRangeGraphAnglePos([]option.RangeVal) | 设置图形随机角度范围 |
slide.WithGenGraphNumber(val int) | 设置图形个数 |
slide.WithEnableGraphVerticalRandom(val bool) | 设置图形水平方向是否随机排序 |
slide.WithRangeDeadZoneDirections(val []DeadZoneDirectionType) | 设置贴图盲区 |
设置资源
builder.SetResources(slide.WithXxx(), ...)
Options | Desc |
---|---|
slide.WithBackgrounds([]image.Image) | 设置主图背景 |
slide.WithGraphImages(images []*GraphImage) | 设置贴图的图形 |
验证码数据
captData, err := capt.Generate()
Method | Desc |
---|---|
GetData() *Block | 获取当前校验的信息 |
GetMasterImage() imagedata.JPEGImageData | 获取主图 |
GetTileImage() imagedata.PNGImageData | 获取缩略图 |
验证码校验
ok := slide.Validate(srcX, srcY, X, Y, paddingValue)
Params | Desc |
---|---|
srcX | 用户交互的 X 值 |
srcY | 用户交互的 Y 值 |
X | 验证码校验的 X 值 |
Y | 验证码校验的 Y 值 |
paddingValue | 控制误差值 |
注意事项
- 拼图块的图像资源(
OverlayImage
,ShadowImage
,MaskImage
)必须有效,否则会触发ImageTypeErr
,ShadowImageTypeErr
或MaskImageTypeErr
。 - 背景图像不能为空,否则会触发
EmptyBackgroundImageErr
。 - 基本模式下,拼图块的 Y 坐标固定;拖拽模式下,Y 坐标可根据
rangeDeadZoneDirections
随机分布。 - 拖拽模式适合需要更高交互自由度的场景,但可能增加用户操作时间。
🖖 旋转验证码(Rotate)
旋转验证码要求用户旋转缩略图使其与主图像的角度对齐,适合需要直观交互的场景。
工作原理
- 生成主图像(
masterImage
):包含旋转后的背景图像,通常为 PNG 格式。 - 生成缩略图(
thumbImage
):从主图像裁剪并应用圆形裁剪和透明度效果,通常为 PNG 格式。 - 用户交互:用户旋转缩略图到目标角度(
block.Angle
),前端捕获旋转角度。 - 验证逻辑:后端比较用户旋转的角度与目标角度是否匹配。
代码示例
package main
import (
"encoding/json"
"fmt"
"image"
"log"
"io/ioutil"
"github.com/wenlng/go-captcha/v2/rotate"
"github.com/wenlng/go-captcha/v2/base/codec"
)
var rotateCapt rotate.Captcha
func init() {
builder := rotate.NewBuilder()
// 可以使用预置的素材资源:https://github.com/wenlng/go-captcha-assets
bgImage, err := loadPng("../resources/bg.png")
if err != nil {
log.Fatalln(err)
}
bgImage1, err := loadPng("../resources/bg1.png")
if err != nil {
log.Fatalln(err)
}
builder.SetResources(
rotate.WithImages([]image.Image{
bgImage,
bgImage1,
}),
)
rotateCapt = builder.Make()
}
func main() {
captData, err := rotateCapt.Generate()
if err != nil {
log.Fatalln(err)
}
blockData := captData.GetData()
if blockData == nil {
log.Fatalln(">>>>> generate err")
}
block, _ := json.Marshal(blockData)
fmt.Println(">>>>>", string(block))
var mBase64, tBase64 string
mBase64, err = captData.GetMasterImage().ToBase64()
if err != nil {
fmt.Println(err)
}
tBase64, err = captData.GetThumbImage().ToBase64()
if err != nil {
fmt.Println(err)
}
fmt.Println(">>>>> ", mBase64)
fmt.Println(">>>>> ", tBase64)
//err = captData.GetMasterImage().SaveToFile("../resources/master.png")
//if err != nil {
// fmt.Println(err)
//}
//err = captData.GetThumbImage().SaveToFile("../resources/thumb.png")
//if err != nil {
// fmt.Println(err)
//}
}
func loadPng(p string) (image.Image, error) {
imgBytes, err := ioutil.ReadFile(p)
if err != nil {
return nil, err
}
return codec.DecodeByteToPng(imgBytes)
}
创建实例
- builder.Make() 旋转式
配置选项
rotate.NewBuilder(rotate.WithXxx(), ...) 或 builder.SetOptions(rotate.WithXxx(), ...)
Options | Desc |
---|---|
rotate.WithImageSquareSize(val int) | 设置主图大小,默认 220x220 |
rotate.WithRangeAnglePos(vals []option.RangeVal) | 设置校验随机角度范围 |
rotate.WithRangeThumbImageSquareSize(val []int) | 设置缩略图大小 |
rotate.WithThumbImageAlpha(val float32) | 设置缩略图透明度 |
设置资源
builder.SetResources(rotate.WithXxx(), ...)
Options | Desc |
---|---|
rotate.WithBackgrounds([]image.Image) | 设置主图图片 |
验证码数据
captData, err := capt.Generate()
Method | Desc |
---|---|
GetData() *Block | 获取当前校验的信息 |
GetMasterImage() imagedata.JPEGImageData | 获取主图 |
GetTileImage() imagedata.PNGImageData | 获取缩略图 |
验证码校验
ok := rotate.Validate(srcAngle, angle, paddingValue)
Params | Desc |
---|---|
srcAngle | 用户交互的角度 |
angle | 验证码校验的角度 |
paddingValue | 控制误差值 |
注意事项
- 背景图像不能为空,否则会触发
EmptyImageErr
。 - 确保背景图像是有效的
image.Image
类型,否则会触发ImageTypeErr
。 - 缩略图会自动应用圆形裁剪效果,确保背景图像分辨率足够以避免模糊。
验证码图像
JPEGImageData
Method | Desc |
---|---|
Get() image.Image | 获取原图像 |
ToBytes() ([]byte, error) | 转为字节数组 |
ToBytesWithQuality(imageQuality int) ([]byte, error) | 指定清晰度转为字节数组 |
ToBase64() (string, error) | 转为 Base64 字符串,带 "data:image/jpeg;base64," 前缀 |
ToBase64Data() (string, error) | 转为 Base64 字符串 |
ToBase64WithQuality(imageQuality int) (string, error) | 指定清晰度转为 Base64 字符串,带 "data:image/jpeg;base64," 前缀 |
ToBase64DataWithQuality(imageQuality int) (string, error) | 指定清晰度转为 Base64 字符串 |
SaveToFile(filepath string, quality int) error | 保存 JPEG 到文件 |
PNGImageData
Method | Desc |
---|---|
Get() image.Image | 获取原图像 |
ToBytes() ([]byte, error) | 转为字节数组 |
ToBase64() (string, error) | 转为 Base64 字符串,带 "data:image/png;base64," 前缀 |
ToBase64Data() (string, error) | 转为 Base64 字符串 |
SaveToFile(filepath string) error | 保存 到文件 |
验证模块
- 文字点选
- 图形点选
- 滑动
- 拖拽
- 旋转
- 抛物线
- 看图选择
- 物品辨认
- ...
扩展&增强
- 基本验证
- 行为检测增强
- 其他因素增强
- 多任务生成模式
- ...
语言支持
- Golang
- NodeJs
- Rust
- Python
- Java
- PHP
- ...
Web
- JavaScript
- Vue
- React
- Angular
- Svelte
- Solid
- ...
App
- UniApp
- WX-Applet
- React Native App
- Flutter App
- Android App
- IOS App
- ...
Deployment Service
- Binary Program
- Docker Image
- ...
赞助一下
如果觉得项目有帮助,可以请作者喝杯咖啡 🍹
LICENSE
Go Captcha source code is licensed under the Apache Licence, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.html