Guard 拦截器
Guard 是方法调用前的中间件,承担鉴权、限流、日志等横切逻辑。v1.3.4 起 Guard 采用错误通道签名——返回 error 表达拒绝,不再需要写响应或 panic。
接口定义
go
type Guard interface {
Guard(ctx fun.Ctx) error
}- 返回
nil:放行,进入下一个 Guard 或业务方法; - 返回
error:短路——后续 Guard 与业务方法不再执行,错误走统一Result响应;返回fun.Error(code, msg)可携带业务错误码。
go
type AuthGuard struct {
Redis *platform.Redis // Guard 也是 Box,依赖自动注入
}
func (g *AuthGuard) Guard(ctx fun.Ctx) error {
token := ctx.State["token"]
if token == "" {
return fun.Error(4010, "未登录")
}
if !g.Redis.Exists("session:" + token) {
return fun.Error(4011, "会话已过期")
}
return nil
}三个挂载层级
go
f := fun.GetFun()
f.BindGuard(&LogGuard{}) // ① 全局:所有服务生效
f.BindService(&AdminSvc{}, &AuthGuard{}) // ② 服务级:可变参数,按注册顺序执行
f.BindRoute("GET", "/admin/*", handler, &AuthGuard{}) // ③ 路由级:自定义路由的处理器前执行执行顺序:全局 → 服务级(各自按注册顺序);路由 Guard 在处理器前按注册顺序执行。任何一层返回 error 即短路。
路由 Guard 的 State
BindRoute 的 Guard 收到的 Ctx.State 已合并 URL 查询与表单参数——token 放查询参数即可鉴权:GET /image/a.png?token=xxx。
Guard 里能拿到什么
Guard 的入参就是 Ctx:
| 字段 | 用途 |
|---|---|
ctx.State | 客户端透传的 token / 自定义标识 |
ctx.Ip | 客户端 IP,做限流、风控 |
ctx.ServiceName / MethodName | 即将调用的端点——可做端点级策略表 |
ctx.RequestCtx | 原生 fasthttp 上下文(Cookie、Header 等) |
从 Cookie 读会话并把校验结果传给服务层的模式:
go
func (g *AuthGuard) Guard(ctx fun.Ctx) error {
sessionId := string(ctx.RequestCtx.Request.Header.Cookie("session"))
user := loadSession(sessionId)
if user == nil {
return fun.Error(4010, "未登录")
}
// 传递给服务层做对象级授权
ctx.RequestCtx.SetUserValue("user", user)
return nil
}
// 服务层
func (s *OrderSvc) Get(dto GetOrderDto) (OrderDto, error) {
user, _ := s.RequestCtx.UserValue("user").(*User)
// ... 对象级授权判断
}推荐姿势:显式端点策略表
中大型项目建议缺省拒绝 + 显式放行表,Guard 只写通用逻辑:
go
// allow 记录哪个服务开放给哪类 Guard 组合;缺省 = 拒绝
var publicEndpoints = map[string]bool{
"UserSvc.Login": true,
"UserSvc.Register": true,
}
func (g *AuthGuard) Guard(ctx fun.Ctx) error {
if publicEndpoints[ctx.ServiceName+"."+ctx.MethodName] {
return nil // 公开端点放行
}
return requireSession(ctx) // 其余一律要求会话
}