package middleware import ( "encoding/json" "time" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/net/ghttp" "easygoadmin/internal/consts" "easygoadmin/utility/cache" "easygoadmin/utility/response" ) // ============================== 租户校验中间件 ============================== // Tenant 租户状态校验 // // 位于身份认证中间件之后,处理规则如下: // - 超管(上下文租户ID=0)直接放行 // - 租户级校验状态与过期时间,摘要缓存 60 秒 func Tenant(r *ghttp.Request) { if IsPublicPath(r.URL.Path) { r.Middleware.Next() return } tenantID := consts.CtxTenantID(r.Context()) if tenantID == 0 { r.Middleware.Next() return } info := loadTenantInfo(r, tenantID) if info != nil { if info.Status != 1 { response.WriteWithCode(r, response.Fail(gerror.NewCode(consts.CodeTenantDisabled)), 1) return } if info.ExpireTime != nil && info.ExpireTime.Time.Before(time.Now()) { response.WriteWithCode(r, response.Fail(gerror.NewCode(consts.CodeTenantExpired)), 1) return } } r.Middleware.Next() } // loadTenantInfo 加载租户摘要 // // 优先读取缓存(60 秒),未命中时回源 TenantLoader 并写缓存 func loadTenantInfo(r *ghttp.Request, tenantID int) *TenantInfo { ck := consts.CacheKeyTenantInfo(tenantID) if v, ok := cache.Get(r.Context(), ck); ok { info := &TenantInfo{} if err := json.Unmarshal([]byte(v), info); err == nil { return info } } if TenantLoader == nil { return nil } info, err := TenantLoader(r.Context(), tenantID) if err != nil || info == nil { glogWarn(r.Context(), "加载租户信息失败 tenantID=%d err=%v", tenantID, err) return nil } if b, err := json.Marshal(info); err == nil { _ = cache.Set(r.Context(), ck, string(b), 60) } return info }