登录验证必须用filter,不能仅靠controller的prepare();因filter是全局拦截入口,可统一控制权限,而prepare()易遗漏、难维护且无法覆盖静态资源或未注册路由。

登录验证该用 Filter 还是 Controller 方法?
Beego 的登录验证逻辑必须放在 Filter 里,不能只靠每个 Controller 的 Prepare() 手动检查。原因很简单:Filter 是全局拦截入口,能统一控制路由访问权限;而 Prepare() 容易遗漏、难维护,且无法覆盖静态资源或未注册的路由。
Beego 1.x 默认使用 beego.InsertFilter() 注册过滤器,推荐在 main.go 初始化阶段注册,作用域设为 beego.BeeApp.Handlers 级别:
beego.InsertFilter("/user/*", beego.BeforeRouter, authFilter)
-
/user/*表示所有以/user/开头的路由(注意末尾通配符) - 必须用
beego.BeforeRouter,否则 session 尚未初始化,GetSession()会返回 nil - 避免写成
/*全局过滤——登录页、注册页、API 公共接口必须放行,否则造成重定向循环
如何从 session 中安全读取用户身份?
Beego 默认用内存或 file 存储 session,StartSession() 必须在 Filter 中显式调用,否则 GetSession() 拿不到数据。常见错误是直接调 GetSession("uid") 却没确认 session 是否已启动或是否过期。
正确做法是先获取 session 实例,再判断 key 是否存在且非空:
func authFilter(ctx *context.Context) {
sess := globalSessions.SessionStart(ctx.ResponseWriter, ctx.Request)
if uid := sess.Get("uid"); uid == nil {
ctx.Redirect(302, "/login")
return
}
// 继续执行
}
- 不要用
sess.Get("uid").(int)强转——类型断言失败会 panic,应先if v, ok := sess.Get("uid").(int); ok - session 过期时间由
beego.BConfig.WebConfig.Session.SessionGCMaxLifetime控制,默认 3600 秒,生产环境建议配合 Redis 后端并设置合理 TTL - 敏感操作(如修改密码)建议额外校验
sess.Get("login_time")时间戳,防止长期有效 session 被复用
登录成功后怎么写 session 并跳转?
登录 Controller 中不能只调 SetSession() 就完事。Beego 的 session 写入依赖 response header,必须确保响应未被提前提交(比如 log 输出、panic、中间件提前 write)。
典型安全写法:
func (c *LoginController) Post() {
username := c.GetString("username")
password := c.GetString("password")
if validUser(username, password) {
sess := c.StartSession()
sess.Set("uid", 123)
sess.Set("username", username)
sess.Set("login_time", time.Now().Unix())
c.Redirect("/user/dashboard", 302)
return
}
c.Data["ErrorMsg"] = "用户名或密码错误"
c.TplName = "login.tpl"
}
-
c.StartSession()必须在c.Redirect()前调用,否则 session 不会写入 cookie - 避免在 redirect 后继续执行逻辑(比如忘记
return),会导致 “http: multiple response.WriteHeader calls” 错误 - 不要把明文密码、token 或敏感字段存入 session;只需存必要标识(如 uid),其他信息按需查库
为什么登录后刷新页面又跳回登录页?
大概率是 session 配置不一致或域名/路径不匹配。Beego 的 session cookie 默认 path 是 /,但如果部署在子路径(如 https://example.com/myapp/),而没改 beego.BConfig.WebConfig.Session.SessionCookiePath,浏览器就不会发送 cookie。
- 检查
beego.BConfig.WebConfig.Session.SessionProvider:开发用memory没问题,但多实例部署必须切到redis或mysql - 确认
beego.BConfig.WebConfig.Session.SessionCookieDomain是否填了错误域名(比如写了localhost却在127.0.0.1访问) - Chrome 浏览器对
SameSite=Lax(Beego 默认值)较严格,若前端用 fetch 提交登录表单,需加credentials: 'include'
session 本身不加密,只做 base64 编码,别指望它防篡改;真正需要权限分级时,应在每次关键操作前查数据库确认角色状态,而不是全信 session 里的 role 字段。











