验证码(CAPTCHA)是“Completely Automated Public Turing test to tell Computers and Humans Apart”(全自动辨别计算机和人类的图灵测试)的缩写,是一种辨别用户是计算机还是人的公共全自动程序。能够避免:歹意破解明码、刷票、论坛灌水,无效避免某个黑客对某一个特定注册用户用特定程序暴力破解形式进行一直的登陆尝试,实际上用验证码是当初很多网站通行的形式,咱们利用比拟繁难的形式实现了这个性能。这个问题能够由计算机生成并评判,然而必须只有人类能力解答。因为计算机无法解答CAPTCHA的问题,所以答复出问题的用户就能够被认为是人类。

传统网站验证码工作机制

  1. 客户端申请服务器获取验证码图片
  2. 服务器生成随机串(验证码值)写入Session,并将验证码值写入到图片中返回给客户端
  3. 客户端输出图片上的字符串提交给服务器验证
  4. 服务器比对客户端提交的字符串值和 Session 中是否匹配,如果匹配则通过验证

因为服务器生成的验证码值从始至终均未返回给客户端,因而,客户端只能从图片中辨认验证码字符串,从而保障人机校验逻辑。

Go的HTTP验证码

思路

Go 语言的 HTTP 服务器默认不反对 Session,因而验证码值须要换个思路存储,以下是不应用 Session 的逻辑

  1. 客户端申请服务器获取验证码ID
  2. 服务器生成验证码 ID,并生成验证码值,将 ID 和值的映射关系记录到内存或缓存,并将 ID 返回给客户端
  3. 客户端依据返回的 ID 申请服务器获取验证码图片
  4. 服务器获取到验证码 ID,从内存或缓存中取出验证码值,将该值写入图片并将图片返回给客户端
  5. 客户端提交验证码 ID(第1步取得)和验证码值给服务器验证
  6. 服务器获取验证码 ID,从内存或缓存中取出验证码值与客户端提交的验证码值比对

示例

  1. 装置验证码依赖
github.com/dchest/captcha
  1. 代码实现
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))   }
  1. 运行

    1. 拜访/captcha/generate取得验证码 ID
    2. 拜访/captcha/image?id=验证码 ID
    3. 拜访/login,并输出第一步的验证码 ID 和第二步的验证码值即可查看验证后果

我的项目地址

https://github.com/xialeistudio/go-http-captcha-example