From 65484abe34879d10cc3c8fdfc1b9e2aeb46552e4 Mon Sep 17 00:00:00 2001 From: wenlng Date: Sun, 23 Jan 2022 18:37:26 +0800 Subject: [PATCH] GetCaptcha is supports thread safety --- README.md | 34 ++++++++++++++---------------- README_zh.md | 48 ++++++++++++++++++++----------------------- captcha/asset.go | 13 ++++++++++++ captcha/captcha.go | 14 +++++++------ tests/base.go | 24 +++++++++++----------- tests/captcha_test.go | 32 +++++++++++++++++++++-------- 6 files changed, 94 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index 8a7c862..b8717e6 100644 --- a/README.md +++ b/README.md @@ -14,22 +14,23 @@

Golang Package go-captcha implements generation and position verification of behavioral CAPTCHAs.

+

⭐️ If it helps you, please give a star.

+ - Github:[https://github.com/wenlng/go-captcha](https://github.com/wenlng/go-captcha) -- Go Example Code:[https://github.com/wenlng/go-captcha-example](https://github.com/wenlng/go-captcha-example) -- Example Code of Vue:[https://github.com/wenlng/go-captcha-vue](https://github.com/wenlng/go-captcha-vue) -- Example Code of React:[https://github.com/wenlng/go-captcha-react](https://github.com/wenlng/go-captcha-react) +- Go Example:[https://github.com/wenlng/go-captcha-example](https://github.com/wenlng/go-captcha-example) +- Vue Example:[https://github.com/wenlng/go-captcha-vue](https://github.com/wenlng/go-captcha-vue) +- React Example:[https://github.com/wenlng/go-captcha-react](https://github.com/wenlng/go-captcha-react) - Online Demo:[http://47.104.180.148:8081/go_captcha_demo](http://47.104.180.148:8081/go_captcha_demo) -- Author Website: [http://witkeycode.com](http://witkeycode.com)
-
- Reward Support -
-
+
Reward Support

+ Reward Support +
+
## Installation of proxy go module in China @@ -88,7 +89,6 @@ func main(){ package main import ( "fmt" - "os" "github.com/wenlng/go-captcha/captcha" ) @@ -178,7 +178,7 @@ func main(){ ``` ### Set Font File Configuration -You can copy the resource files under the "__example/resources" to the directory of your project. +You can copy the resource files under the "https://github.com/wenlng/go-captcha-example/tree/main/resources" to the directory of your project. ```go package main import ( @@ -391,7 +391,7 @@ func main(){ } ``` -#### Other +## Other ```go package main import ( @@ -401,16 +401,14 @@ import ( ) func main(){ - capt := captcha.GetCaptcha() - path, _ := os.Getwd() // ==================================================== // Method: ClearAssetCacheWithPath(paths []string) bool; // Desc: Clear Cache // ==================================================== - capt.ClearAssetCacheWithPaths([]string{ + captcha.ClearAssetCacheWithPaths([]string{ path + "/__example/resources/images/1.jpg", - path + "/__example/resources/images/2.jpg", + path + "/__example/resources/fonts/fonts.ttf", }) // ==================================================== @@ -427,7 +425,7 @@ func main(){ } ``` -### Generate Captcha Data +## Generate Captcha Data ```go package main import ( @@ -459,10 +457,9 @@ func main(){ } ``` -### Api Params Of Fronted Example +## Api Params ``` // Example: Get captcha data -API = http://....../captcha/captcha-data Respose Data = { "code": 0, "image_base64": "...", @@ -471,7 +468,6 @@ API = http://....../captcha/captcha-data } // Example: Post check data -API = http://....../captcha/check-data Request Data = { dots: "x1,y1,x2,y2,...." key: "......" diff --git a/README_zh.md b/README_zh.md index 26924cc..567412f 100644 --- a/README_zh.md +++ b/README_zh.md @@ -16,22 +16,23 @@ go-captcha, 一个简洁易用、交互友好、高安全性的"行为式验证码" Go库 ,采用 “验证码展示-采集用户行为-验证行为数据” 为流程,用户无需键盘手动输入,极大优化传统验证码用户体验不佳的问题,支持PC端及移动端,支持前端Vue、React...等项目。

+

⭐️ 如果能帮助到你,记得随手给点一个star。

+ - Github:[https://github.com/wenlng/go-captcha](https://github.com/wenlng/go-captcha) -- Go实例代码:[https://github.com/wenlng/go-captcha-example](https://github.com/wenlng/go-captcha-example) -- Vue实例代码:[https://github.com/wenlng/go-captcha-vue](https://github.com/wenlng/go-captcha-vue) -- React实例代码:[https://github.com/wenlng/go-captcha-react](https://github.com/wenlng/go-captcha-react) +- 后端Go实例:[https://github.com/wenlng/go-captcha-example](https://github.com/wenlng/go-captcha-example) +- 前端Vue实例:[https://github.com/wenlng/go-captcha-vue](https://github.com/wenlng/go-captcha-vue) +- 前端React实例:[https://github.com/wenlng/go-captcha-react](https://github.com/wenlng/go-captcha-react) - 在线演示:[http://47.104.180.148:8081/go_captcha_demo](http://47.104.180.148:8081/go_captcha_demo) -- 作者网站: [http://witkeycode.com](http://witkeycode.com)
-
- Reward Support -
-
+
Reward Support

+ Reward Support +
+
## 中国Go模块代理 @@ -90,7 +91,6 @@ func main(){ package main import ( "fmt" - "os" "github.com/wenlng/go-captcha/captcha" ) @@ -179,7 +179,7 @@ func main(){ ``` #### 设置字体文件 -你可以拷贝实例中 "__example/resources" 的图片资源和字体文件到你的项目中使用。 +你可以拷贝实例仓库中 "https://github.com/wenlng/go-captcha-example/tree/main/resources" 的图片资源和字体文件到你的项目中使用。 ```go package main import ( @@ -194,7 +194,7 @@ func main(){ path, _ := os.Getwd() // ==================================================== // Method: SetFont(fonts []string); - // Desc: 设置验证码字体 + // Desc: 设置验证码字体,自动仅读取一次并加载到内存中缓存,如需重置可清除缓存 // ==================================================== capt.SetFont([]string{ path + "/__example/resources/fonts/fzshengsksjw_cu.ttf", @@ -218,7 +218,7 @@ func main(){ path, _ := os.Getwd() // ==================================================== // Method: SetBackground(color []string); - // Desc: 设置验证码背景图 + // Desc: 设置验证码背景图,自动仅读取一次并加载到内存中缓存,如需重置可清除缓存 // ==================================================== capt.SetBackground([]string{ path + "/__example/resources/images/1.jpg", @@ -362,7 +362,7 @@ func main(){ // ==================================================== // Method: SetThumbBackground(colors []string); - // Desc:设置缩略图的随机图像背景 + // Desc:设置缩略图的随机图像背景,自动仅读取一次并加载到内存中缓存,如需重置可清除缓存 // ==================================================== capt.SetThumbBackground([]string{ path + "/__example/resources/images/r1.jpg", @@ -396,7 +396,7 @@ func main(){ } ``` -#### 其它 +## 其它 ```go package main import ( @@ -405,18 +405,16 @@ import ( "github.com/wenlng/go-captcha/captcha" ) -func main(){ - capt := captcha.GetCaptcha() - +func main(){ path, _ := os.Getwd() // ==================================================== // Method: ClearAssetCacheWithPath(paths []string) bool; - // Desc: 根据路径消除对应的资源缓存 + // Desc: 根据路径清除应资源的缓存 // ==================================================== - capt.ClearAssetCacheWithPaths([]string{ + captcha.ClearAssetCacheWithPaths([]string{ path + "/__example/resources/images/1.jpg", - path + "/__example/resources/images/2.jpg", - }) + path + "/__example/resources/fonts/fonts.ttf", + }) // ==================================================== // Method: captcha.CheckPointDist(sx, sy, dx, dy, width, height int64) bool; @@ -426,13 +424,13 @@ func main(){ // ==================================================== // Method: captcha.CheckPointDistWithPadding(sx, sy, dx, dy, width, height, padding int64) bool; - // Desc: 校验点的位置 + // Desc: 校验点的位置,可设置文本范围的偏移量 // ==================================================== captcha.CheckPointDistWithPadding(0, 30, 0, 30, 30, 30, 5) } ``` -### 生成验证码数据 +## 生成验证码数据 ```go package main import ( @@ -464,10 +462,9 @@ func main(){ } ``` -### 在 __example 中的前端在数据请求或提交验证数据时的格式: +## 前端在数据请求或提交验证数据时的格式: ``` // Example: 获取验证码数据 -API = http://....../captcha/captcha-data Respose Data = { "code": 0, "image_base64": "...", @@ -476,7 +473,6 @@ API = http://....../captcha/captcha-data } // Example: 提交校验数据 -API = http://....../captcha/check-data Request Data = { dots: "x1,y1,x2,y2,...." key: "xxxxxx" diff --git a/captcha/asset.go b/captcha/asset.go index b37e017..4b16374 100644 --- a/captcha/asset.go +++ b/captcha/asset.go @@ -44,4 +44,17 @@ func clearAssetCache(paths []string) bool { */ func setAssetCache(path string, content []byte, force bool) bool { return assets.SetAssetCache(path, content, force) +} + +// ============================================= +// Call API +// ============================================= +// ClearAssetCacheWithPaths is a function +/** + * @Description: 根据路径清除资源缓存 + * @param paths + * @return bool + */ +func ClearAssetCacheWithPaths(paths []string) bool { + return clearAssetCache(paths) } \ No newline at end of file diff --git a/captcha/captcha.go b/captcha/captcha.go index 0f82049..a124267 100644 --- a/captcha/captcha.go +++ b/captcha/captcha.go @@ -17,6 +17,7 @@ import ( "math" "math/rand" "strings" + "sync" "time" ) @@ -59,7 +60,8 @@ type Captcha struct { captchaDraw *Draw } -var clickCaptcha *Captcha +var _instance *Captcha +var _once sync.Once // NewCaptcha is a function /** @@ -76,15 +78,15 @@ func NewCaptcha() *Captcha { // GetCaptcha is a function /** - * @Description: 获取点选验证码 + * @Description: 获取点选验证码,是安全的 * @return *Captcha */ func GetCaptcha() *Captcha { - if clickCaptcha == nil { - clickCaptcha = NewCaptcha() - } + _once.Do(func() { + _instance = NewCaptcha() + }) - return clickCaptcha + return _instance } // SetRangChars is a function diff --git a/tests/base.go b/tests/base.go index dac0eb4..0979280 100644 --- a/tests/base.go +++ b/tests/base.go @@ -30,18 +30,18 @@ func getPWD() string { func getCaptcha() *captcha.Captcha { capt := captcha.GetCaptcha() - capt.SetFont([]string{ - getPWD() + "/__example/resources/fonts/fzshengsksjw_cu.ttf", - getPWD() + "/__example/resources/fonts/hyrunyuan.ttf", - }) - - capt.SetBackground([]string{ - getPWD() + "/__example/resources/images/1.jpg", - getPWD() + "/__example/resources/images/2.jpg", - getPWD() + "/__example/resources/images/3.jpg", - getPWD() + "/__example/resources/images/4.jpg", - getPWD() + "/__example/resources/images/5.jpg", - }) + //capt.SetFont([]string{ + // getPWD() + "/__example/resources/fonts/fzshengsksjw_cu.ttf", + // getPWD() + "/__example/resources/fonts/hyrunyuan.ttf", + //}) + // + //capt.SetBackground([]string{ + // getPWD() + "/__example/resources/images/1.jpg", + // getPWD() + "/__example/resources/images/2.jpg", + // getPWD() + "/__example/resources/images/3.jpg", + // getPWD() + "/__example/resources/images/4.jpg", + // getPWD() + "/__example/resources/images/5.jpg", + //}) return capt } diff --git a/tests/captcha_test.go b/tests/captcha_test.go index a80b7a7..fa7ee5b 100644 --- a/tests/captcha_test.go +++ b/tests/captcha_test.go @@ -14,9 +14,25 @@ import ( "log" "os" "strings" + "sync" "testing" ) +// go test -race base.go captcha_test.go +func TestGetCaptchaGoroutine(t *testing.T) { + var wg sync.WaitGroup + n := 30 + wg.Add(n) + for i := 0; i < n; i++ { + go func() { + t.Logf(">>> %p\n", getCaptcha()) + wg.Done() + }() + } + + wg.Wait() +} + func TestImageSize(t *testing.T) { capt := getCaptcha() fmt.Println(capt) @@ -143,7 +159,7 @@ func TestImageFontDistort(t *testing.T) { func TestRangAnglePos(t *testing.T) { capt := getCaptcha() - rang := []*captcha.RangeVal{ + rang := []captcha.RangeVal{ {1, 15}, {15, 30}, {30, 45}, @@ -167,13 +183,13 @@ func TestRangAnglePos(t *testing.T) { func TestThumbBackground(t *testing.T) { capt := getCaptcha() - capt.SetThumbBackground([]string{ - getPWD() + "/__example/resources/images/thumb/r1.jpg", - getPWD() + "/__example/resources/images/thumb/r2.jpg", - getPWD() + "/__example/resources/images/thumb/r3.jpg", - getPWD() + "/__example/resources/images/thumb/r4.jpg", - getPWD() + "/__example/resources/images/thumb/r5.jpg", - }) + //capt.SetThumbBackground([]string{ + // getPWD() + "/__example/resources/images/thumb/r1.jpg", + // getPWD() + "/__example/resources/images/thumb/r2.jpg", + // getPWD() + "/__example/resources/images/thumb/r3.jpg", + // getPWD() + "/__example/resources/images/thumb/r4.jpg", + // getPWD() + "/__example/resources/images/thumb/r5.jpg", + //}) dots, b64, tb64, key, err := capt.Generate() if err != nil {