package middleware import ( "context" "net/http" db "server/internal/db/sqlc" "server/internal/pkg/cache" "server/internal/pkg/errs" "server/internal/pkg/httputil" "strings" "github.com/go-chi/chi/v5" ) const ( IsAdminKey contextKey = "is_admin" ) type AuthMiddleware struct { queries *db.Queries cache *cache.Caches } func NewAuthMiddleware(queries *db.Queries, cache *cache.Caches) *AuthMiddleware { return &AuthMiddleware{ cache: cache, queries: queries, } } func (m *AuthMiddleware) Middleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() claims, ok := GetClaims(ctx) if !ok || claims.UserID == 0 { httputil.Fail(w, errs.ErrUnauthorized) return } // 判断是否有管理员权限 目前只判断uid是否为1 isAdmin := userIsAdmin(claims.UserID) if isAdmin { ctx = context.WithValue(ctx, IsAdminKey, isAdmin) next.ServeHTTP(w, r.WithContext(ctx)) return } hasPermission, err := userHasApiPermission(ctx, r, m.queries, claims.UserID, m.cache) if err != nil { httputil.Fail(w, err) return } if !hasPermission { httputil.Fail(w, errs.ErrPermissionDenied) return } next.ServeHTTP(w, r) }) } func userIsAdmin(uid int32) bool { if uid == 1 { return true } return false } func userHasApiPermission(ctx context.Context, r *http.Request, queries *db.Queries, uid int32, cache *cache.Caches) (bool, error) { var ( apis []db.GetSysUserApisRow err error ) apis, ok := cache.SysUserApisCache.GetIfPresent(uid) if !ok { apis, err = queries.GetSysUserApis(ctx, uid) if err != nil { return false, err } cache.SysUserApisCache.Set(uid, apis) } requestPath := chi.RouteContext(r.Context()).RoutePattern() requestPath = strings.TrimPrefix(requestPath, "/api") requestMethod := r.Method for _, api := range apis { if api.Path == requestPath && api.Method == requestMethod { return true, nil } } return false, nil }