功能详解 02 · 登录、退出与 Session:Cookie ttms_sid 如何认人
个人主页会编程的土豆欢迎来访作者简介后端学习者❄️个人专栏数据结构与算法数据库leetcode✨那些你一个人走过的夜路终将化作照亮未来的光系列《影院票务 GO》功能详解 · 第 02 篇对应代码handlers/auth.go·store/session.go·handlers/app.go·static/js/app.js前置第 01 篇注册知识点篇blogs/12-Cookie与Session登录态.md一、背景HTTP 无状态网站怎么「记住你」HTTP 协议本身是无状态的服务器处理完一次请求就「忘了」你是谁但购票系统需要连续认人——从登录到选座、下单不能每点一次按钮都重新输入密码。常见方案Session会话 Cookie浏览器存 Session ID。本项目约定项目值Cookie 名ttms_sidCookie 值32 字节随机数的 hex 字符串Session ID服务端存储内存map[string]*sessionData有效期24 小时NewSessionStore(24 * time.Hour)HttpOnlytrueJS 读不到防 XSS 偷 Cookie重要区分认证Authentication登录时验证用户名密码 ——APILogin。识别Identification之后每次请求用 Cookie 找 Session ——Sessions.Get。鉴权Authorization识别后检查能不能做某操作 —— 第 03 篇的requireAdmin。本篇聚焦登录 / 退出 / Session 读写。二、用户视角登录打开/login输入user/user123或admin/admin123。点登录 → 页面跳转管理员 →/admin顾客 →/顶栏显示昵称、「订单」「退出」管理员还多一个「后台」。退出点「退出」→ 调/api/logout→ 回首页顶栏变回「登录 / 注册」。刷新页面为什么仍登录因为浏览器自动带上 Cookiettms_sid服务端用 ID 查内存 map取出*models.User。三、完整流程图3.1 登录成功[浏览器 POST /api/login {username, password}] ▼ [APILogin] GetUserByUsername ▼ [CheckPassword] 比对 MD5(输入库中salt) 与 库中password ▼ [Sessions.Create(w, user)] ├─ newID() → sessionId ├─ map[sessionId] {User, ExpiresAt} └─ Set-Cookie: ttms_sidsessionId; HttpOnly; MaxAge86400 ▼ [utils.OK] 返回 {id, username, nickname, role} ▼ [app.js doLogin] role1 ? /admin : /3.2 后续任意请求[浏览器 GET /orders Cookie: ttms_sidabc...] ▼ [handler] a.currentUser(r) ▼ [Sessions.Get(r)] 读 Cookie → 查 map → 未过期则 *User ▼ [Render / 业务逻辑] 模板里 {{.User.Nickname}}3.3 退出[POST /api/logout] ▼ [Sessions.Destroy] ├─ delete(map, sessionId) └─ Set-Cookie: ttms_sid; MaxAge-1 让浏览器删 Cookie ▼ [utils.OK]四、路由与 Handlerhandlers/routes.gomux.HandleFunc(/login, a.PageLogin) mux.HandleFunc(/api/login, a.APILogin) mux.HandleFunc(/api/logout, a.APILogout) mux.HandleFunc(/api/me, a.APIMe)4.1 APILoginhandlers/auth.gofunc (a *App) APILogin(w http.ResponseWriter, r *http.Request) { if r.Method ! http.MethodPost { utils.Fail(w, 方法不允许) return } var req struct { Username string json:username Password string json:password } if err : utils.DecodeJSON(r, req); err ! nil { utils.Fail(w, 参数错误) return } u, err : dao.GetUserByUsername(strings.TrimSpace(req.Username)) if err ! nil { utils.Fail(w, err.Error()) return } if u nil || !utils.CheckPassword(req.Password, u.Salt, u.Password) { utils.Fail(w, 用户名或密码错误) return } a.Sessions.Create(w, u) utils.OK(w, map[string]interface{}{ id: u.ID, username: u.Username, nickname: u.Nickname, role: u.Role, }) }安全细节用户不存在和密码错误同一句话「用户名或密码错误」—— 避免攻击者枚举哪些用户名已注册。校验通过后才CreateSession失败不写 Cookie。4.2 APILogoutfunc (a *App) APILogout(w http.ResponseWriter, r *http.Request) { a.Sessions.Destroy(w, r) utils.OK(w, nil) }4.3 APIMe —— 当前登录用户是谁func (a *App) APIMe(w http.ResponseWriter, r *http.Request) { u : a.currentUser(r) if u nil { utils.Fail(w, 未登录) return } utils.OK(w, u) }可用于前端 SPA 拉用户信息本项目主要在服务端模板里注入User。五、SessionStore 源码精读文件store/session.go。5.1 数据结构与常量const cookieName ttms_sid type sessionData struct { User *models.User ExpiresAt time.Time } type SessionStore struct { mu sync.RWMutex data map[string]*sessionData ttl time.Duration secure bool }dataSession ID → 用户 过期时间。mu读写锁多个 HTTP 请求并发访问 map 必须加锁否则 race condition。ttlSession 寿命App 初始化时传24 * time.Hour。handlers/app.gofunc NewApp(cfg config.Config) *App { return App{ Cfg: cfg, Sessions: store.NewSessionStore(24 * time.Hour), } }5.2 Create —— 登录写 Sessionfunc (s *SessionStore) Create(w http.ResponseWriter, user *models.User) { id : newID() s.mu.Lock() s.data[id] sessionData{User: user, ExpiresAt: time.Now().Add(s.ttl)} s.mu.Unlock() http.SetCookie(w, http.Cookie{ Name: cookieName, Value: id, Path: /, HttpOnly: true, MaxAge: int(s.ttl.Seconds()), }) }newID()func newID() string { b : make([]byte, 16) _, _ rand.Read(b) return hex.EncodeToString(b) // 32 个 hex 字符 }Cookie 字段解释字段作用Namettms_sid项目自定义避免与别的站冲突Path/全站有效HttpOnlydocument.cookie读不到MaxAge秒数浏览器到期自动删响应头类似Set-Cookie: ttms_sida1b2c3...; Path/; MaxAge86400; HttpOnly注意Session 里存的是*models.User指针含密码哈希字段——只在服务端内存不发给浏览器。5.3 Get —— 每次请求认人func (s *SessionStore) Get(r *http.Request) *models.User { c, err : r.Cookie(cookieName) if err ! nil || c.Value { return nil } s.mu.RLock() defer s.mu.RUnlock() item, ok : s.data[c.Value] if !ok || time.Now().After(item.ExpiresAt) { return nil } return item.User }三种「未登录」情况统一返回nil没有 CookieSession ID 不在 map服务端重启、被 Destroy、GC 清掉已过期。handlers/app.go封装func (a *App) currentUser(r *http.Request) *models.User { return a.Sessions.Get(r) }模板templates/header.html{{if .User}} span classuser{{.User.Nickname}}/span button onclicklogout()退出/button {{else}} a href/login登录/a {{end}}5.4 Destroy —— 退出func (s *SessionStore) Destroy(w http.ResponseWriter, r *http.Request) { c, err : r.Cookie(cookieName) if err nil { s.mu.Lock() delete(s.data, c.Value) s.mu.Unlock() } http.SetCookie(w, http.Cookie{Name: cookieName, Value: , Path: /, MaxAge: -1}) }服务端删 map 浏览器删 Cookie双保险。5.5 过期清理 gcLoopfunc (s *SessionStore) gcLoop() { t : time.NewTicker(10 * time.Minute) for range t.C { now : time.Now() s.mu.Lock() for k, v : range s.data { if now.After(v.ExpiresAt) { delete(s.data, k) } } s.mu.Unlock() } }NewSessionStore里go s.gcLoop()启动后台 goroutine防止过期 Session 占内存。即使用户不退出24 小时后Get也会判过期。5.6 RefreshUser扩展func (s *SessionStore) RefreshUser(r *http.Request, user *models.User) { // 更新 Session 内 User 指针并续期 }改昵称等场景可刷新 Session当前项目注册后未单独调用了解即可。六、前端credentials 与跳转逻辑static/js/app.jsasync function api(url, options {}) { const res await fetch(url, { headers: { Content-Type: application/json, ...(options.headers || {}) }, credentials: same-origin, // 关键同源请求携带 Cookie ...options, }); ... } async function doLogin(e) { e.preventDefault(); const fd new FormData(e.target); try { const user await api(/api/login, { method: POST, body: JSON.stringify({ username: fd.get(username), password: fd.get(password) }), }); location.href user.role 1 ? /admin : /; } catch (err) { alert(err.message); } return false; } async function logout() { await api(/api/logout, { method: POST, body: {} }); location.href /; }credentials: same-origin含义默许fetch不带 Cookie设为same-origin后对/api/login的响应Set-Cookie会被保存后续/api/*和页面请求都会带上ttms_sid。登录后按role分流role 1→ 管理后台role 0→ 顾客首页。与models.RoleAdmin、RoleCustomer常量一致。七、Session 存什么为什么不存密码Session 存完整*models.User包括Password、Salt字段——只在服务器内存。每次Get直接返回该指针handler 可立刻用u.ID、u.IsAdmin()不必再查库。权衡优点缺点快无 DB 压力改用户 role/昵称后 Session 内是旧数据直到重新登录实现简单服务重启 Session 全丢用户要重新登录课设够用多机部署不能共享内存 map生产环境常用Redis Session或JWT本项目注释写明「内存 Session适合课程项目」。八、与页面/API 的配合场景是否必须登录怎么判断首页/否currentUser可为 nil仍显示片单选座/seats/是requireLogin→ 302/login下单 API是currentUser nil→ JSON Fail顶栏昵称可选有 User 就显示登录态贯穿所有带Cookie的请求未登录访问公开页不会报错只是User为空。九、调试技巧Chrome DevTools → Application → Cookies看是否有ttms_sid。Network → 任意请求 → Request HeadersCookie: ttms_sid...。重启 Go 程序内存 Session 清空Cookie 仍在但Get返回 nil —— 表现为「Cookie 在但显示未登录」。curl 模拟curl -c jar.txt -X POST http://localhost:8080/api/login -H Content-Type: application/json -d {\username\:\user\,\password\:\user123\} curl -b jar.txt http://localhost:8080/api/me十、小结登录验证密码后SessionStore.Create生成随机 ID内存 map Set-Cookiettms_sid。之后Get(r)读 Cookie 查 map得到*User过期或无效返回nil。退出Destroy删 map 并MaxAge-1清 Cookie。前端fetch必须credentials: same-origin才能收发 Cookie。内存 Session 24h TTL 10 分钟 GC重启丢失——课设清晰上线需换方案。一句话「登录成功后服务器发一张『(sessionId) 号手环』给浏览器 Cookie以后每次请求亮手环内存里查对应用户。」下一篇03-顾客与管理员权限.md——role字段如何驱动页面与 API 的requireLogin/requireAdmin/apiUser。

相关新闻

​​​​​​功能详解 01 · 用户注册:从表单到数据库一行

​​​​​​功能详解 01 · 用户注册:从表单到数据库一行

🥰个人主页:会编程的土豆(欢迎来访) 💎作者简介:后端学习者 ❄️个人专栏:数据结构与算法,数据库,leetcode ✨那些你一个人走过的夜路,终将化作照亮未来的光 …

2026/7/28 1:27:12 阅读更多 →
目前 Claude / GPT 的订阅建议与反代避坑

目前 Claude / GPT 的订阅建议与反代避坑

半年来在 Claude 和 GPT 的 CLI 上累计消耗了约 30,000$ 用量的 tokens(Claude : GPT 2: 1,Fable 5 出来之后 GPT 用量为 0)。这期间关于模型对比体验的文章断断续续其实写了不少,但 Agent 相关技术和概念迭代太快,新…

2026/7/28 1:27:11 阅读更多 →
HarmonyOS应用开发实战:猫猫大作战-@Extend 的使用

HarmonyOS应用开发实战:猫猫大作战-@Extend 的使用

前言 Extend 装饰器用于为特定组件类型扩展样式方法,与 Styles 的通用属性集合不同,Extend 可以访问组件特有的属性。 本文以「猫猫大作战」的 Text 标题样式为锚点,讲解 Extend 的使用。 提示:本系列不讲 ArkTS 基础语法与环境…

2026/7/28 1:26:11 阅读更多 →

最新新闻

如何快速配置游戏MOD:虎符台一站式管理解决方案终极指南

如何快速配置游戏MOD:虎符台一站式管理解决方案终极指南

如何快速配置游戏MOD:虎符台一站式管理解决方案终极指南 【免费下载链接】legion-seal 虎符台/Legion Seal,全面战争游戏MOD管理器,技术栈:Tauri 2 Vue TailwindCSS 项目地址: https://gitcode.com/zeyl/legion-seal 全面…

2026/7/28 1:37:15 阅读更多 →
AI应用开发实战:从零到工程化部署的完整学习路径解析

AI应用开发实战:从零到工程化部署的完整学习路径解析

如果你正在寻找一套能真正带你从零开始、系统掌握AI应用开发的实战教程,那么你很可能已经陷入了两个极端:要么是B站上那些看似“保姆级”实则东拼西凑、不成体系的零散视频,要么是动辄数千元、理论脱离实践的付费课程。前者让你学得一头雾水,后者则让你投入巨大却难以落地。…

2026/7/28 1:37:15 阅读更多 →
SQL Server性能突降排查:从CPU飙高到执行计划分析实战

SQL Server性能突降排查:从CPU飙高到执行计划分析实战

1. 先确认问题:是SQL本身,还是环境或数据变了?面试官问“昨天50毫秒,今天5秒,CPU飙到90%”,这其实是在考察你面对线上突发性能问题的第一反应和排查思路。很多人一上来就埋头看SQL执行计划、加索引&#xf…

2026/7/28 1:37:15 阅读更多 →
暗黑破坏神2网页存档编辑器:零安装修改游戏存档的终极指南

暗黑破坏神2网页存档编辑器:零安装修改游戏存档的终极指南

暗黑破坏神2网页存档编辑器:零安装修改游戏存档的终极指南 【免费下载链接】d2s-editor 项目地址: https://gitcode.com/gh_mirrors/d2/d2s-editor 还在为暗黑破坏神2的角色培养进度缓慢而烦恼吗?想要快速体验不同装备组合和技能搭配却苦于没有合…

2026/7/28 1:37:15 阅读更多 →
AI辅助编程实战:蒙特卡洛模拟构建NBA选秀预测模型

AI辅助编程实战:蒙特卡洛模拟构建NBA选秀预测模型

最近在技术圈和体育圈的交汇处,一场别开生面的“编程马拉松”吸引了我的注意。一群背景各异的年轻人,在短短24小时内,仅凭一份NBA历史数据和AI代码生成工具,就构建出了一款能够预测NBA选秀结果的“球探应用”。这听起来像是科幻电影里的情节,但它真实地发生在上海世博中心…

2026/7/28 1:37:15 阅读更多 →
AI旅行助手终极指南:三步打造你的智能旅行规划师

AI旅行助手终极指南:三步打造你的智能旅行规划师

AI旅行助手终极指南:三步打造你的智能旅行规划师 【免费下载链接】ai-travel-agent AI Travel Agent 项目地址: https://gitcode.com/gh_mirrors/ai/ai-travel-agent 想要告别繁琐的旅行规划,让AI智能助手帮你搞定一切?AI旅行助手正是…

2026/7/28 1:36:15 阅读更多 →

日新闻

告别臃肿!3步让你的暗影精灵笔记本重获新生

告别臃肿!3步让你的暗影精灵笔记本重获新生

告别臃肿!3步让你的暗影精灵笔记本重获新生 【免费下载链接】OmenSuperHub Control Omen laptop performance, fan speeds, and keyboard lighting, and unlock power limits. 项目地址: https://gitcode.com/gh_mirrors/om/OmenSuperHub 你是否也曾为官方Om…

2026/7/28 0:00:43 阅读更多 →
RAG必踩坑!财报法规检索不准?这款开源工具让答案浮出水面,准确率飙升98.7%!

RAG必踩坑!财报法规检索不准?这款开源工具让答案浮出水面,准确率飙升98.7%!

做 RAG 的人应该都踩过这个致命的坑:把几百页的财报、法规、技术手册扔给向量库,问一个具体问题,搜出来的全是沾边但没用的内容 —— 关键信息要么被硬切块拆碎了,要么藏在几十条结果的最下面。语义相似≠真正相关,这个…

2026/7/28 0:00:43 阅读更多 →
抖音视频文案提取工具全指南:免费2026版、手机App、在线工具一网打尽

抖音视频文案提取工具全指南:免费2026版、手机App、在线工具一网打尽

2026年做短视频运营,从抖音上扒文案早就不是偷偷抄笔记的事了。我刚开始做内容的时候,每天刷半小时抖音,手动把爆款视频的口播敲进备忘录,一条2分钟的视频得花十来分钟,碰到语速快的还要反复回听。后来试了一圈工具&am…

2026/7/28 0:00:43 阅读更多 →

周新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档,可以直接使用!系统支持图片、视频、摄像头等多种方式检测裂缝,功能强大实用。 1数据集6000张 8各类别

2026/7/27 4:33:59 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像! pubg绝地求生目标检测数据集 1分类:e_body,14905个标签,txt格式 共计14244张图,99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/27 6:31:56 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别: allies enemy tag图片总量:7247张训练集:5139张验证集:1425张测试集:683张标注状态:全部已标注,即拿即用数据格式:支持YOLO格式及其他格式&#…

2026/7/27 4:01:12 阅读更多 →

月新闻