beego默认关闭xsrf防护,必须显式启用:一是在conf/app.conf中配置enablexsrf=true、xsrfkey(需强随机)和xsrfexpire=3600;二是在main.go中beego.run()前设置bconfig.webconfig对应字段;模板中用c.xsrfformhtml()注入_token,前后端分离时支持x-xsrftoken请求头传递。

怎么在 beego 里开启 XSRF 防护
必须显式启用,beego 默认关闭 XSRF 防护。只改配置不生效,还要确保 XSRFKey 是足够随机的字符串,且不能硬编码在代码里长期复用。
两种等效方式,选其一即可:
- 在
conf/app.conf中添加三行(注意缩进和空格):enablexsrf = truexsrfkey = 61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1oxsrfexpire = 3600 - 或在
main.go的beego.Run()调用前设置:beego.BConfig.WebConfig.EnableXSRF = truebeego.BConfig.WebConfig.XSRFKey = "61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o"beego.BConfig.WebConfig.XSRFExpire = 3600
注意:xsrfexpire 单位是秒,默认值其实是 60 秒(不是 3600),文档和实际源码不一致,建议显式设为 3600 避免意外过期。
模板里怎么插入 XSRF Token
仅对 GET 渲染页面、POST/PUT/DELETE 提交的场景有效;GET 请求本身不校验,也不需要插入。
控制器中生成 token 并传入模板:
func (c *XsrfController) Get() {
c.Data["xsrfdata"] = template.HTML(c.XSRFFormHTML())
c.TplName = "test_xsrf.html"
}
模板中直接嵌入(不要加引号、不要转义):
渲染后会自动变成一个隐藏 input:<input type="hidden" name="_xsrf" value="abc123...">
别手动拼接 _xsrf 字段——c.XSRFFormHTML() 内部已处理签名、过期、CSRF cookie 绑定逻辑。
前后端分离时怎么传 XSRF Token
beego 原生支持从请求头读取 token,不依赖 cookie 携带,这对跨域 API 场景很关键。
前端拿到 token 后(比如从登录成功响应头 X-CSRF-Token 或首次 GET 页面响应中提取),后续所有状态变更请求必须带上:
- Header 名:优先用
X-Xsrftoken,次选用X-CsrfToken - 值:就是服务端下发的完整 token 字符串(不含
_xsrf=前缀)
beego 源码中 CheckXSRFCookie() 函数明确按此顺序查找:
先查表单字段 _xsrf → 再查 X-Xsrftoken header → 最后查 X-CsrfToken header。
这意味着你完全可以用 fetch + headers: {'X-Xsrftoken': token} 方式调用 API,无需 cookie 共享。
为什么 POST 提交还报 417 或 422 错误
常见原因不是配置没开,而是 token 生命周期或来源不匹配:
-
422 Unprocessable Entity:请求里根本没提供 token —— 检查前端是否漏传_xsrf字段或 header,或后端模板没调用c.XSRFFormHTML() -
417 Expectation Failed:token 校验失败 —— 多半是XSRFKey在不同实例间不一致(比如多节点部署时用了默认 key 或本地生成的随机值),或 token 已过期(注意:cookie 过期时间由xsrfexpire控制,但 token 签名也绑定 session ID,session 失效也会导致校验失败) - 使用了
beego.XSRFKEY(旧写法)而非beego.BConfig.WebConfig.XSRFKey(新写法):v2.x 后推荐统一走BConfig,否则可能被忽略
调试时可临时在 controller 中打印:beego.Debug("xsrf cookie:", c.Ctx.Request.Header.Get("X-Xsrftoken"))
确认 token 是否真实到达。
真正容易被忽略的是:XSRF 机制和 session 强绑定,如果关了 session(sessionon = false),XSRF 自动失效,且不会报错,只会静默跳过校验。











