feat(httpauth): initial release — provider-agnostic HTTP auth middleware
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.
This commit is contained in:
44
cache.go
Normal file
44
cache.go
Normal file
@@ -0,0 +1,44 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user