gin中需在认证中间件中用c.set("user", user)存用户信息,并在handler中用c.mustget("user")取出传入html模板,模板中须用{{with .user}}或{{if .user}}安全访问字段,避免nil panic。

在 Gin 中间件里把用户信息塞进 c 上下文
Gin 本身不自带用户会话管理,你得自己解析 token、查数据库或从 session 取出当前登录用户,然后用 c.Set() 存进去。这步必须在所有需要用户信息的路由之前执行,否则模板里取不到。
常见错误是中间件没注册、或者注册顺序错了(比如写在 r.GET(...) 后面),导致 c.Get() 返回 nil。
- 推荐在认证中间件中完成:验证 JWT 或 session 成功后,调用
c.Set("user", user) -
user通常是个结构体(如struct{ID uint, Name string}),确保它可被序列化(字段首字母大写) - 别用
c.Set("user", *userPtr)这种带指针的值传给模板——Gin 模板引擎对指针支持不稳定,容易 panic
模板渲染时从 c 提取并传入 html/template
Gin 的 c.HTML() 不自动把 c.Get() 的内容塞进模板,你得手动解包再传。这是最常漏掉的一环:光 Set 了,却没 Get 出来传给 HTML()。
示例代码片段:
c.HTML(http.StatusOK, "index.html", gin.H{
"Title": "首页",
"User": c.MustGet("user"), // 注意这里要显式取
})
-
c.MustGet()比c.Get()更安全,它会在 key 不存在时 panic,帮你早发现问题 - 如果用户未登录,
c.MustGet("user")会 panic,建议先if u, ok := c.Get("user"); ok { ... }判断 - 传进模板的键名(如
"User")要和模板里写的变量名一致,大小写敏感
HTML 模板里安全访问 User 字段并避免空指针
Go 模板默认不处理 nil 值,直接写 {{ .User.Name }} 在用户未登录时会报 invalid memory address or nil pointer dereference。
- 用
with控制块包裹:{{ with .User }}{{ .Name }}{{ end }} - 或用
if判断:{{ if .User }}欢迎 {{ .User.Name }}{{ else }}请登录{{ end }} - 别在模板里调用方法(如
.User.IsAdmin()),除非该方法明确返回值且 receiver 是值类型;方法调用失败静默忽略,难调试
为什么不用全局变量或 context.WithValue?
有人想绕过 c.Set(),直接往 context.Context 里塞用户,再在 handler 里取——Gin 的 c.Request.Context() 确实能存,但 c.HTML() 完全不读它,所以模板拿不到。
也有人试过定义全局 map 存用户 ID → 用户结构体,再在模板里查——这破坏请求隔离,高并发下数据错乱,且无法绑定生命周期(比如用户登出后缓存没清)。
真正可靠的做法就一条路:中间件 Set → handler MustGet 并传入 HTML() → 模板用 with/if 安全展开。
最容易被忽略的是中间件注册顺序和模板中对 nil 的防御性写法——这两处一错,页面直接 500,连日志都不一定打出来。











