feat: 注册流程强制图形验证码

SSR 注册页与 /api/register 共用 CaptchaService,防刷同时保留换一张无 JS 刷新。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-29 21:13:24 +08:00
parent 5e623f67fb
commit 54f5de07a4
12 changed files with 111 additions and 6 deletions

34
services/captcha_test.go Normal file
View File

@@ -0,0 +1,34 @@
package services
import "testing"
func TestCaptchaGenerateAndVerify(t *testing.T) {
s := NewCaptchaService()
id, svg, err := s.Generate()
if err != nil {
t.Fatal(err)
}
if id == "" || len(svg) < 20 {
t.Fatalf("bad captcha output id=%q svgLen=%d", id, len(svg))
}
s.mu.Lock()
ans := s.entries[id].answer
s.mu.Unlock()
if ans == "" {
t.Fatal("empty stored answer")
}
if !s.Verify(id, ans) {
t.Fatalf("correct answer %q should pass", ans)
}
if s.Verify(id, ans) {
t.Fatal("captcha should be one-time")
}
id2, _, err := s.Generate()
if err != nil {
t.Fatal(err)
}
if s.Verify(id2, "XXXX") {
t.Fatal("wrong answer should fail")
}
}