buffalo 的 auth 中间件不支持自动登录,需手动实现“记住我”功能:在 sessionsaver 后、authorize 前插入中间件,解析签名 cookie 并填充 session,同时登出时删除 cookie 并考虑密码变更后的 token 失效。

Buffalo 框架里 auth 中间件不支持自动登录,得自己加逻辑
Buffalo 默认的 auth 中间件(比如 buffalo-auth 插件或手写 session 登录)只处理显式登录请求,不会检查 cookie 或 token 自动恢复用户。所谓“记住我”,本质是服务端在用户勾选后下发长期有效的凭证(如签名 cookie),后续请求到来时主动验证并设好 c.Session().Set("user_id", ...)。
关键不是“加个开关”,而是绕过默认登录流程,在 App().Use() 阶段插入自己的中间件,且必须放在 auth 中间件之前,否则 session 已被清空或跳过。
- 不能把自动登录逻辑写在登录成功后的 handler 里——那只是单次行为,无法覆盖后续所有请求
- 不能依赖前端 localStorage 存 token——Buffalo 默认走服务端 session,cookie 才是可信通道
- 签名 cookie 必须用
c.Session().Options()设置MaxAge和HttpOnly: true,否则浏览器可能不持久化或 JS 可窃取
怎么生成和校验“记住我” cookie
推荐用 gob 编码 + hmac 签名组合,避免明文 ID 被篡改。Buffalo 的 session 库本身不提供独立签名校验能力,得手动做:
// 示例:生成 remember_me cookie
func setRememberMeCookie(c buffalo.Context, userID uint) {
data := map[string]interface{}{"id": userID, "ts": time.Now().Unix()}
b, _ := json.Marshal(data)
sig := hmac.New(sha256.New, []byte(App().Options().Session.Secret))
sig.Write(b)
cookieVal := base64.URLEncoding.EncodeToString(append(b, sig.Sum(nil)...))
c.Cookies().Set("remember_me", cookieVal, 30*24*60*60, "/", "", false, true)
}
校验时反向解码、拆分、重算签名比对。注意时间戳可加宽限(比如 ±15 分钟),防止客户端时间偏差导致反复失效。
Buffalo框架 1.0.1 版本源码包下载,适合需要错误处理改进、依赖更新、render.Download 注释和 request logger 调整的 v1 项目。
- 别用纯 base64 —— 没防篡改能力,用户改 ID 就能越权
- 别把密码哈希塞进 cookie —— “记住我”凭据应和登录凭据分离,即使泄露也不影响主账户安全
- 每次成功自动登录后,建议刷新 cookie 过期时间(renew),并记录最后使用时间用于风控
自动登录中间件要避开 session 冲突
Buffalo 的 Session 中间件会在每个请求开头读取并解密 cookie,但此时 c.Session().Get("user_id") 还是空的。你得在它之后、但在业务 handler 之前,检查 remember_me cookie 并手动填充 session:
func RememberMeMiddleware(next buffalo.Handler) buffalo.Handler {
return func(c buffalo.Context) error {
if uID := getRememberMeUserID(c); uID > 0 {
// 注意:必须调用 Set,且不能覆盖已有 user_id(比如已登录)
if c.Session().Get("user_id") == nil {
c.Session().Set("user_id", uID)
c.Session().Save() // 强制写回,否则下次请求还是空
}
}
return next(c)
}
}
// 然后在 actions/app.go 里:
app.Use(FirstHandler) // 如日志
app.Use(Recover)
app.Use(RequestLogger)
app.Use(AddCSRF)
app.Use(SessionSaver) // Buffalo 默认 session 中间件
app.Use(RememberMeMiddleware) // ✅ 放在这里,紧接 SessionSaver 之后
app.Use(Authorize) // 此时 session 已有 user_id,auth 才能放行
- 如果
RememberMeMiddleware放在SessionSaver前面,c.Session()还没初始化,会 panic - 如果放在
Authorize后面,用户已经因未登录被拒,中间件根本不会执行 -
c.Session().Save()不是可选的——Buffalo 默认只在响应头已写入时才自动保存,而中间件里属于“提前写”,必须显式触发
登出时务必清除 remember_me cookie
用户点“退出登录”时,除了清空 session,必须显式删除 remember_me cookie,否则下次访问还会自动登录:
func Logout(c buffalo.Context) error {
c.Session().Clear()
c.Session().Save()
c.Cookies().Delete("remember_me")
return c.Redirect(302, "/")
}
容易忽略的是:如果用户在多个设备登录并勾选“记住我”,一个设备登出不应影响其他设备。所以不要在数据库里全局失效 remember token——除非你额外实现了 token 黑名单机制,否则就靠 cookie 过期和单次清除即可。
真正麻烦的是“用户修改密码后自动使所有 remember_me 失效”。这需要你在 User 模型里加 remember_salt 字段,每次改密时更新它,并把它混入 cookie 签名计算。否则攻击者拿到旧 cookie 仍能长期登录。










