Go语言实战案例:用户注册与登录(无数据库)

在实际 Web 应用中,用户注册与登录 是最常见的功能之一。

本案例不使用数据库,而是将用户信息存储在内存中,主要用于学习和演示。


一、功能目标

    1. 注册接口 /register
    • • 提交用户名和密码
    • • 保存到内存 map 中
    • • 返回注册成功信息
    1. 登录接口 /login
    • • 验证用户名和密码
    • • 登录成功后,创建 Session
    • • 在 Cookie 中存储 session_id
    1. 用户信息接口 /profile
    • • 读取 Cookie 中的 Session
    • • 返回当前登录用户信息

二、核心知识点

  • 表单数据解析r.FormValue("username")
  • 内存用户存储map[string]string(用户名 → 密码)
  • Session 管理
    • map[string]string(session_id → username)
    • • Cookie 存储 Session ID
  • 随机 Session ID 生成crypto/rand + encoding/hex

三、完整代码

go 复制代码
package main

import (
    "crypto/rand"
    "encoding/hex"
    "fmt"
    "net/http"
    "sync"
)

var (
    users       = make(map[string]string) // 用户存储: username -> password
    sessions    = make(map[string]string) // 会话存储: session_id -> username
    mu          sync.Mutex
)

// 生成随机 Session ID
func generateSessionID() string {
    b := make([]byte, 16)
    rand.Read(b)
    return hex.EncodeToString(b)
}

// 注册
func registerHandler(w http.ResponseWriter, r *http.Request) {
    if r.Method != http.MethodPost {
        http.Error(w, "只支持 POST", http.StatusMethodNotAllowed)
        return
    }

    username := r.FormValue("username")
    password := r.FormValue("password")

    if username == "" || password == "" {
        http.Error(w, "用户名和密码不能为空", http.StatusBadRequest)
        return
    }

    mu.Lock()
    defer mu.Unlock()

    if _, exists := users[username]; exists {
        http.Error(w, "用户已存在", http.StatusConflict)
        return
    }

    users[username] = password
    fmt.Fprintf(w, "注册成功: %s\n", username)
}

// 登录
func loginHandler(w http.ResponseWriter, r *http.Request) {
    if r.Method != http.MethodPost {
        http.Error(w, "只支持 POST", http.StatusMethodNotAllowed)
        return
    }

    username := r.FormValue("username")
    password := r.FormValue("password")

    mu.Lock()
    storedPwd, exists := users[username]
    mu.Unlock()

    if !exists || storedPwd != password {
        http.Error(w, "用户名或密码错误", http.StatusUnauthorized)
        return
    }

    // 创建 Session
    sessionID := generateSessionID()
    mu.Lock()
    sessions[sessionID] = username
    mu.Unlock()

    http.SetCookie(w, &http.Cookie{
        Name:  "session_id",
        Value: sessionID,
        Path:  "/",
    })

    fmt.Fprintf(w, "登录成功: %s\n", username)
}

// 获取用户信息
func profileHandler(w http.ResponseWriter, r *http.Request) {
    cookie, err := r.Cookie("session_id")
    if err != nil {
        http.Error(w, "未登录", http.StatusUnauthorized)
        return
    }

    mu.Lock()
    username, exists := sessions[cookie.Value]
    mu.Unlock()

    if !exists {
        http.Error(w, "会话无效", http.StatusUnauthorized)
        return
    }

    fmt.Fprintf(w, "当前登录用户: %s\n", username)
}

func main() {
    http.HandleFunc("/register", registerHandler)
    http.HandleFunc("/login", loginHandler)
    http.HandleFunc("/profile", profileHandler)

    fmt.Println("服务器已启动:http://localhost:8080")
    http.ListenAndServe(":8080", nil)
}

四、运行与测试

    1. 启动服务器
go 复制代码
go run main.go
    1. 注册用户
bash 复制代码
curl -X POST -d "username=tom&password=123456" http://localhost:8080/register

返回:

makefile 复制代码
注册成功: tom
    1. 登录用户
bash 复制代码
curl -i -X POST -d "username=tom&password=123456" http://localhost:8080/login

返回(同时设置了 Set-Cookie):

makefile 复制代码
登录成功: tom
    1. 获取当前用户信息
bash 复制代码
curl --cookie "session_id=xxxxx" http://localhost:8080/profile

返回:

makefile 复制代码
当前登录用户: tom

五、注意事项

  • 内存存储
    • • 服务器重启后数据会丢失
    • • 不适合生产环境
  • 安全性
    • • 真实环境必须加密存储密码(如 bcrypt
    • • 建议使用 HTTPS 保护 Cookie
  • Session 过期
    • • 生产环境要设置 Session 过期时间并定期清理

六、进阶扩展

  • • 使用 bcrypt 对密码进行哈希处理
  • • 将用户数据和 Session 存储到 Redis数据库
  • • 添加 登出接口 清除 Session
  • • 使用第三方 Session 管理库(如 gorilla/sessions

相关推荐
妙蛙种子3111 分钟前
【Java设计模式 | 创建者模式】 原型模式
java·开发语言·后端·设计模式·原型模式
阿聪谈架构8 分钟前
第07章(下):LangGraph 工作流进阶 —— 检查点、人工介入与多 Agent 协作
人工智能·后端
希望永不加班13 分钟前
SpringBoot 配置绑定:@ConfigurationProperties
java·spring boot·后端·spring
悟空码字14 分钟前
MySQL性能优化的天花板:10条你必须掌握的顶级SQL分析技巧
java·后端·mysql
Soofjan18 分钟前
Go interface 源码:iface、itab、getitab 与动态派发
后端
Soofjan20 分钟前
Go interface:语法、接口值与常见坑
后端
写Cpp的小黑黑21 分钟前
WebSocket 协议、帧结构与 MTU 详解
后端
white-persist27 分钟前
【vulhub spring CVE-2018-1270】CVE-2018-1270 Spring Messaging 远程命令执行漏洞 完整复现详细分析解释
java·服务器·网络·数据库·后端·python·spring
神奇小汤圆1 小时前
Spring-Boot-泛型封装-这8个坑让我调了3天
后端
深挖派1 小时前
GoLand 2026.1 安装配置与环境搭建 (保姆级图文教程)
后端·golang·编辑器·go·goland