captcha.VerifyString验证逻辑 7 months ago
函数签名
根据 dchest/captcha
的源码,VerifyString
的定义如下:
func VerifyString(id string, digits string) bool
id
: 验证码的唯一标识符,用于从内部存储中检索对应的验证码答案。digits
: 用户输入的验证码字符串(通常是一串数字)。
返回值是一个布尔值,表示用户输入是否与存储的验证码答案匹配。
逻辑分析
VerifyString
的核心逻辑可以分解为以下步骤:
输入清洗:
- 函数首先对用户输入的
digits
字符串进行处理,去除其中的空格和逗号。 - 这是为了提高容错性,允许用户输入类似
"1 2 3 4"
或"1,2,3,4"
这样的格式,而不会直接失败。 - 处理后,
digits
只保留数字字符。如果字符串中包含除数字、空格、逗号外的其他字符,函数会直接返回false
。
- 函数首先对用户输入的
从存储中获取真实答案:
- 使用
id
从全局存储(globalStore
)中检索对应的验证码答案。 globalStore.Get(id, true)
被调用,其中true
表示在获取答案后立即从存储中删除该验证码(确保验证码是一次性的)。- 如果
id
不存在(即没有找到对应的验证码),返回nil
,函数会返回false
。
- 使用
答案比较:
- 将清洗后的
digits
(转换为字节切片)与存储中的真实答案(也是字节切片)进行比较。 - 使用
bytes.Equal
函数逐字节比较两者是否完全一致。 - 如果一致,返回
true
;否则,返回false
。
- 将清洗后的
一次性验证:
- 如前所述,调用
globalStore.Get(id, true)
后,无论验证结果如何,该验证码都会从存储中被删除。这确保了验证码只能被验证一次,防止重放攻击。
- 如前所述,调用
源码实现
以下是 VerifyString
的简化源码(基于 dchest/captcha
的实现):
func VerifyString(id string, digits string) bool {
if digits == "" {
return false
}
// 去除空格和逗号
cleaned := strings.ReplaceAll(digits, " ", "")
cleaned = strings.ReplaceAll(cleaned, ",", "")
// 检查是否只包含数字
for _, c := range cleaned {
if c < '0' || c > '9' {
return false
}
}
// 从存储中获取真实答案并删除
realDigits := globalStore.Get(id, true)
if realDigits == nil {
return false
}
// 比较答案
return bytes.Equal([]byte(cleaned), realDigits)
}
逻辑特点
简单直接:
VerifyString
不涉及复杂的加密或哈希,直接比较字节内容,依赖于存储中的原始答案。
输入容错:
- 允许空格和逗号,但严格要求只包含数字字符,增加了用户输入的灵活性,同时保持安全性。
一次性使用:
- 通过删除机制确保验证码不能重复使用,符合 CAPTCHA 的典型设计目标。
依赖存储:
- 函数的正确性依赖于
globalStore
的状态。如果存储中没有对应的id
,验证必然失败。
- 函数的正确性依赖于
使用示例
假设你生成了一个验证码,ID 为 "abc123"
,答案为 "1234"
:
import "github.com/dchest/captcha"
func main() {
// 假设已经生成了验证码 "1234",ID 为 "abc123"
id := "abc123"
// 用户输入正确的情况
result := captcha.VerifyString(id, "1234") // 返回 true
println(result)
// 用户输入包含空格
result = captcha.VerifyString(id, "1 2 3 4") // 返回 false(因已被删除)
println(result)
// 用户输入错误
result = captcha.VerifyString(id, "5678") // 返回 false(ID已失效)
println(result)
}
注意事项
- 安全性:
dchest/captcha
的文档中提到,这种验证码可能被高级 OCR(光学字符识别)算法破解,因此不建议用于高安全需求的场景。 - 存储管理:默认使用内存存储(
globalStore
),有过期时间(默认 10 分钟)和垃圾回收机制。如果需要持久化,可以通过实现Store
接口自定义存储。
- 上一篇: 用户登陆逻辑
- 下一篇: 提示词-prompt