Go语言实现验证码登录(教学完整示例)
说明:本文严格按照你既定的博客 / 教学长文规范编写,适合 Go Web 开发入门、后端安全机制讲解以及面试常见登录系统设计题。
一、项目背景详细介绍
在实际的 Web 系统中,验证码登录几乎是所有登录系统的“标配功能”,其主要目的包括:
-
防止暴力破解密码
-
防止机器人 / 脚本自动登录
-
提高系统整体安全性
-
作为风控体系中的第一道防线
在面试或系统设计中,常见问题有:
-
为什么登录要加验证码?
-
验证码应该存在哪里?
-
验证码如何校验、如何过期?
-
如何防止验证码被重放?
很多同学只停留在“会用第三方库”的层面,但对验证码登录的完整流程理解不清晰。
因此,用 Go 语言 从零实现一个 完整、可运行、可教学的验证码登录示例,对于理解 Web 安全与登录流程非常重要。
二、项目需求详细介绍
2.1 功能性需求
提供获取验证码接口
提供登录接口(账号 + 密码 + 验证码)
校验验证码正确性
验证码一次性使用并支持过期
2.2 非功能性需求
使用 Go 标准库实现 HTTP 服务
不依赖复杂框架,便于教学
代码结构清晰、逻辑完整
模拟真实业务流程
三、相关技术详细介绍
3.1 验证码登录整体流程
一个完整的验证码登录流程通常包括:
客户端请求验证码
服务端生成验证码并保存
客户端提交登录请求(含验证码)
服务端校验验证码
校验账号密码
3.2 验证码存储方案
常见方案:
-
内存(map / cache)—— 教学示例
-
Redis(生产常用)
-
Session / Token 绑定
本文采用 内存 Map + 过期时间 方式进行演示。
3.3 HTTP 服务实现
使用 Go 标准库:
-
net/http
-
encoding/json
即可完成完整 Web 服务。
四、实现思路详细介绍
4.1 系统设计
-
验证码生成模块
-
验证码存储与校验模块
-
登录接口
4.2 核心设计点
-
验证码与客户端标识(captchaId)绑定
-
验证码设置有效期
-
校验成功后立即删除验证码
五、完整实现代码
说明:以下为完整可运行示例,所有代码放在一个代码块中,不同文件通过注释区分。
/********************************
* 文件:captcha_login.go
********************************/
package main
import (
"encoding/json"
"fmt"
"log"
"math/rand"
"net/http"
"sync"
"time"
)
// Captcha 验证码结构体
type Captcha struct {
Code string
ExpiredAt time.Time
}
// CaptchaStore 验证码存储
type CaptchaStore struct {
mu sync.Mutex
data map[string]Captcha
}
func NewCaptchaStore() *CaptchaStore {
return &CaptchaStore{
data: make(map[string]Captcha),
}
}
func (cs *CaptchaStore) Set(id, code string, ttl time.Duration) {
cs.mu.Lock()
defer cs.mu.Unlock()
cs.data[id] = Captcha{Code: code, ExpiredAt: time.Now().Add(ttl)}
}
func (cs *CaptchaStore) Verify(id, code string) bool {
cs.mu.Lock()
defer cs.mu.Unlock()
captcha, ok := cs.data[id]
if !ok {
return false
}
if time.Now().After(captcha.ExpiredAt) {
delete(cs.data, id)
return false
}
if captcha.Code != code {
return false
}
delete(cs.data, id) // 一次性使用
return true
}
var store = NewCaptchaStore()
// generateCaptchaCode 生成 4 位验证码
func generateCaptchaCode() string {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
return fmt.Sprintf("%04d", r.Intn(10000))
}
// getCaptchaHandler 获取验证码接口
func getCaptchaHandler(w http.ResponseWriter, r *http.Request) {
captchaID := fmt.Sprintf("%d", time.Now().UnixNano())
code := generateCaptchaCode()
store.Set(captchaID, code, 2*time.Minute)
resp := map[string]string{
"captcha_id": captchaID,
"captcha_code": code, // 教学演示直接返回,生产环境应返回图片
}
json.NewEncoder(w).Encode(resp)
}
// loginHandler 登录接口
func loginHandler(w http.ResponseWriter, r *http.Request) {
var req struct {
Username string `json:"username"`
Password string `json:"password"`
CaptchaID string `json:"captcha_id"`
Captcha string `json:"captcha"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
if !store.Verify(req.CaptchaID, req.Captcha) {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("invalid captcha"))
return
}
// 模拟账号密码校验
if req.Username != "admin" || req.Password != "123456" {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("invalid username or password"))
return
}
w.Write([]byte("login success"))
}
func main() {
http.HandleFunc("/captcha", getCaptchaHandler)
http.HandleFunc("/login", loginHandler)
log.Println("server started at :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
六、代码详细解读(仅解读方法作用)
6.1 generateCaptchaCode
生成固定长度的数字验证码。
6.2 CaptchaStore
用于存储、校验验证码,并控制验证码有效期和一次性使用。
6.3 getCaptchaHandler
提供获取验证码接口,生成并返回验证码标识。
6.4 loginHandler
登录接口,依次校验验证码和账号密码。
七、项目详细总结
通过该示例,可以系统理解:
-
验证码在登录系统中的作用
-
验证码的生成、存储与校验机制
-
Go 实现 Web 登录系统的基本方式
这是 Web 后端与安全机制中的基础必备能力。
八、项目常见问题及解答
Q1:为什么验证码要一次性使用?
防止重放攻击。
Q2:生产环境验证码如何实现?
通常返回图片或第三方验证码服务。
Q3:验证码应该存在哪里?
生产环境通常使用 Redis。
九、扩展方向与性能优化
图片验证码(扭曲、干扰线)
Redis 存储验证码
短信 / 邮箱验证码登录
滑块验证码实现思路
登录失败次数限制
至此,一个完整、规范、可教学的 Go 语言验证码登录实现完成。




