- 客户端请求服务器获取验证码图片
- 服务器生成随机串(验证码值)写入Session,并将验证码值写入到图片中返回给客户端
- 客户端输入图片上的字符串提交给服务器验证
- 服务器比对客户端提交的字符串值和 Session 中是否匹配,如果匹配则通过验证
由于服务器生成的验证码值从始至终均未返回给客户端,因此,客户端只能从图片中识别验证码字符串,从而保证人机校验逻辑。
Go 语言的 HTTP 服务器默认不支持 Session,因此验证码值需要换个思路存储,以下是不使用 Session 的逻辑
- 客户端请求服务器获取验证码ID
- 服务器生成验证码 ID,并生成验证码值,将 ID 和值的映射关系记录到内存或缓存,并将 ID 返回给客户端
- 客户端根据返回的 ID 请求服务器获取验证码图片
- 服务器获取到验证码 ID,从内存或缓存中取出验证码值,将该值写入图片并将图片返回给客户端
- 客户端提交验证码 ID(第1步获得)和验证码值给服务器验证
- 服务器获取验证码 ID,从内存或缓存中取出验证码值与客户端提交的验证码值比对
- 安装验证码依赖
go get -u github.com/dchest/captcha
- 代码实现
package main
import (
"fmt"
"github.com/dchest/captcha"
"log"
"net/http"
)
func main() {
// 获取验证码 ID
http.HandleFunc("/captcha/generate", func(w http.ResponseWriter, r *http.Request) {
id := captcha.NewLen(6)
if _, err := fmt.Fprint(w, id); err != nil {
log.Println("generate captcha error", err)
}
})
// 获取验证码图片
http.HandleFunc("/captcha/image", func(w http.ResponseWriter, r *http.Request) {
id := r.URL.Query().Get("id")
if id == "" {
http.Error(w, "Bad Request", http.StatusBadRequest)
return
}
w.Header().Set("Content-Type", "image/png")
if err := captcha.WriteImage(w, id, 120, 80); err != nil {
log.Println("show captcha error", err)
}
})
// 业务处理
http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
log.Println("parseForm error", err)
http.Error(w, "Internal Error", http.StatusInternalServerError)
return
}
// 获取验证码 ID 和验证码值
id := r.FormValue("id")
value := r.FormValue("value")
// 比对提交的验证码值和内存中的验证码值
if captcha.VerifyString(id, value) {
fmt.Fprint(w, "ok")
} else {
fmt.Fprint(w, "mismatch")
}
})
log.Fatal(http.ListenAndServe(":8080", nil))
}
- 运行
- 访问/captcha/generate获得验证码 ID
- 访问/captcha/image?id=验证码 ID
- 访问/login,并输入第一步的验证码 ID 和第二步的验证码值即可查看验证结果
完整代码 。
原文链接:
[1]
计算机: 计算机
[2]
图灵测试: 图灵测试
[3]
程序: 程序/71525
[4]
刷票: 刷票/6540942