静态资源默认不应走业务鉴权中间件,但若在挂载AuthMiddleware后调用r.Static(),则所有静态请求都会被拦截;正确做法是将Static路由置于中间件注册之前,或改用受控路由+c.File()实现权限校验。

静态资源(如 /static/js/app.js、/uploads/avatar.png)默认不应走业务鉴权中间件,但一旦你主动用 router.Static() 或 router.StaticFS() 暴露了目录,又在全局或分组上挂了权限中间件,就可能意外拦截——这不是 Gin 的 bug,而是中间件执行链的必然结果。
为什么 router.Static() 也会被中间件拦截
Gin 的 Static 和 StaticFS 本质是注册了一组 GET 路由(例如 GET /static/*filepath),它们和其他路由一样参与匹配和中间件链。只要该路由落在某个已挂载中间件的分组或全局作用域内,就会被执行。
- 错误写法:
r.Use(AuthMiddleware())后调用r.Static("/static", "./assets")→ 所有静态请求都先过鉴权 - 正确做法:把静态路由放在中间件注册之前,或单独用无中间件的引擎/分组托管
- 注意:
router.NoRoute()不影响Static,它只兜底未匹配的动态路由
StaticFS 下路径越界与权限绕过的风险
gin.FileSystem 默认不校验路径遍历(如 ..),若直接暴露根目录或用户上传目录,攻击者可构造 /static/../config.yaml 读取敏感文件。
- 必须用
http.Dir包裹并限制根目录,例如:http.Dir("./public"),而非http.Dir(".") - 若需权限控制(如仅登录用户能看某类图片),别依赖
StaticFS,改用普通GET路由 + 中间件 +c.File()显式读取 - 示例安全读取:
c.File(fmt.Sprintf("./uploads/%s", filename)),前提是filename已白名单过滤或正则校验
按角色/登录态控制静态资源访问的实操方案
真要对静态资源做权限判定(比如管理员才能下载报表模板),就不能用 Static,而应走标准路由 + 中间件 + 文件流输出。
- 定义受控路由:
admin.GET("/download/template.xlsx", DownloadTemplateHandler) - 在
DownloadTemplateHandler中调用c.Get("role")判断是否为"admin" - 权限通过后,用
c.Header("Content-Disposition", "attachment; filename=template.xlsx")+c.File("./templates/template.xlsx") - 避免用
c.Redirect()跳转到/static/,那会绕过中间件校验
最易被忽略的一点:Gin 的 Static 路由匹配优先级高于自定义 GET,所以如果你写了 r.Static("/static", "./public") 又想对 /static/private/ 做权限控制,必须确保没有更宽泛的 Static 覆盖它——要么拆分目录,要么全部改用受控路由。











