Provides SetTokenData for upstream AuthMiddleware implementations, EnrichmentMiddleware and AuthzMiddleware compatible with any provider that calls SetTokenData, ClaimsPermissionProvider for JWT-embedded permissions, and CachedPermissionProvider for TTL-backed runtime resolution via any Cache implementation.
45 lines
1.4 KiB
Go
45 lines
1.4 KiB
Go
package httpauth
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"code.nochebuena.dev/go/rbac"
|
|
)
|
|
|
|
// Cache abstracts the caching backend for permission masks.
|
|
// Implementations are typically backed by Valkey or Redis.
|
|
type Cache interface {
|
|
Get(ctx context.Context, key string) (int64, bool, error)
|
|
Set(ctx context.Context, key string, value int64, ttl time.Duration) error
|
|
}
|
|
|
|
type cachedPermissionProvider struct {
|
|
inner rbac.PermissionProvider
|
|
cache Cache
|
|
ttl time.Duration
|
|
}
|
|
|
|
// NewCachedPermissionProvider wraps inner with a TTL-based cache layer.
|
|
// Cache key format: "rbac:{uid}:{resource}".
|
|
// On cache miss, falls through to inner and populates the cache.
|
|
// On cache error, falls through to inner silently — never fails due to cache unavailability.
|
|
// For explicit invalidation, delete "rbac:{uid}:{resource}" directly via your Cache.
|
|
func NewCachedPermissionProvider(inner rbac.PermissionProvider, cache Cache, ttl time.Duration) rbac.PermissionProvider {
|
|
return &cachedPermissionProvider{inner: inner, cache: cache, ttl: ttl}
|
|
}
|
|
|
|
func (p *cachedPermissionProvider) ResolveMask(ctx context.Context, uid, resource string) (rbac.PermissionMask, error) {
|
|
key := fmt.Sprintf("rbac:%s:%s", uid, resource)
|
|
if val, ok, err := p.cache.Get(ctx, key); err == nil && ok {
|
|
return rbac.PermissionMask(val), nil
|
|
}
|
|
mask, err := p.inner.ResolveMask(ctx, uid, resource)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
_ = p.cache.Set(ctx, key, int64(mask), p.ttl)
|
|
return mask, nil
|
|
}
|