Beego 无内置防盗链中间件,需通过 Prepare 方法或 Filter 拦截 Referer 实现;Prepare 适合保护特定控制器资源,Filter 适用于全局静态路径(如 /static/uploads/);须处理空 Referer、协议切换清空、Host 匹配等边界情况,且仅作辅助防护。

Beego 本身不提供开箱即用的「防盗链」中间件,但可以通过 Controller 的 Prepare 方法或自定义 Filter 拦截请求,检查 Referer 请求头来实现基础防盗链。关键在于:是否允许空 Referer、如何配置白名单、以及静态资源(如 /static/)是否走 Beego 路由。
在 Prepare 中检查 Referer 是否合法
这是最轻量、最可控的方式,适合保护特定控制器下的资源(比如图片下载接口、附件预览等)。Beego 会在每个请求进入 Get/Post 前调用 Prepare,你在这里做校验并提前终止即可。
常见错误现象:Referer 为空却被拒绝(导致直接访问或微信内嵌页失败);正则匹配过于宽松(如只匹配域名不锚定开头);未考虑 HTTPS → HTTP 的 Referer 清空行为。
-
Referer为空时通常应放行(浏览器直接地址栏输入、书签、部分 App 内 WebView),除非业务强要求来源 - 白名单建议用
strings.HasPrefix或strings.Contains判断,避免正则开销;若需通配,用net/url.Parse提取 host 后比对 - 注意:HTTPS 页面加载 HTTP 资源时,浏览器会清空
Referer;反之亦然 —— 所以混合协议站点要预留空 Referer 通道
func (c *ImageController) Prepare() {
referer := c.Ctx.Request.Referer()
if referer == "" {
c.Abort("403")
return
}
u, err := url.Parse(referer)
if err != nil || u.Host == "" {
c.Abort("403")
return
}
allowedHosts := []string{"example.com", "app.example.com"}
allowed := false
for _, h := range allowedHosts {
if u.Host == h || strings.HasSuffix(u.Host, "."+h) {
allowed = true
break
}
}
if !allowed {
c.Abort("403")
}
}
用 Filter 全局拦截静态资源路径
如果想统一保护 /static/uploads/ 下所有文件,又不想让这些请求绕过 Beego(比如用 Nginx 直接服务),就得注册一个路径匹配的 Filter。注意:Beego 的 InsertFilter 对静态文件默认不生效 —— 因为 StaticDir 是独立路由分支,必须显式绑定到对应前缀。
使用场景:后端托管用户上传的图片、PDF,且不允许外站 hotlink;同时希望日志、权限、防盗链逻辑集中管控。
- Filter 注册位置必须在
main.go的beego.Router/beego.StaticDir之前,否则不触发 - 匹配路径要用
beego.FILTER_BEFORE_ROUTER,不能用AFTER_RECOVERY—— 否则静态文件已返回,拦截失效 - Beego 1.12+ 中,
StaticDir默认不经过 Controller 生命周期,所以Prepare对/static/下请求无效,必须用 Filter
func checkReferer(r *context.Context) {
path := r.Input.URL()
if strings.HasPrefix(path, "/static/uploads/") {
referer := r.Request.Referer()
if referer == "" {
r.Abort(403)
return
}
u, _ := url.Parse(referer)
if u == nil || !strings.HasSuffix(u.Host, "example.com") {
r.Abort(403)
return
}
}
}
beego.InsertFilter("/static/uploads/*", beego.FILTER_BEFORE_ROUTER, checkReferer)
Referer 校验的边界情况和兼容性问题
真实环境中,Referer 不可靠,且大量合法访问会缺失或被篡改。不要把它当作唯一鉴权手段,仅作辅助限制。
- Chrome 扩展、某些 PWA、Electron 应用可能不带
Referer;iOS 微信内置浏览器在跳转时也常清空它 - 用户可手动修改请求头绕过,所以该机制仅防“懒人盗链”,不防恶意爬虫或脚本批量请求
- 若搭配 CDN(如 Cloudflare),需确认 CDN 是否透传
Referer;部分 CDN 默认 strip,需开启Origin Cache Control或自定义规则 - Beego 日志中
Referer字段名是Referer(注意大小写),不是Referrer(少一个 r)—— 写错会导致永远匹配不到
真正需要强防盗的资源(比如付费内容、限时素材),得结合签名 URL(如 ?sign=xxx&expire=1732122000)或登录态 Session 校验。Referer 检查只是第一道低门槛过滤,写太重反而误伤正常流量。


















